Materials and Methods
2.1 Detailed Protocols
To improve reproducibility (e.g. Dickie et al., 2018; Shea et al.,
2023), enable open data science (e.g. Fredston and Lowndes, 2024), and
aid in the initiation of new eDNA biomonitoring projects, we have
published detailed, step-by-step protocols for many of the methods
described, including specific materials used, photographs, and
additional methodological notes not possible to include here. See Shea
and Boehm for sample collection and filtering (2023b),
for DNA extractions (2023c),
for PCR amplification (2023d),
and for shipping samples (2023e).
Additionally, we have published all data and code for replicating our
analyses via Dryad (Shea & Boehm,
2024), including FASTQ files and eDNA datasets (pre-processing &
post-processing). Through Dryad and Zenodo, our modified Anacapa
Container and scripts for bioinformatics (Shea & Boehm,
2023a), as well as a GitHUb repository including an R Markdown file
that reproduces all methods & results detailed here (Shea & Boehm,
2023f) can also be accessed.
2.2 Sampling Site
To better understand spatial and temporal differences in eDNA signals
in a complex coastal environment, we sought a rocky intertidal field
location that had consistent, large, accessible tide pools that were
fully isolated from one another at some low tides but interconnected
during other parts of their exposure period. We selected the intertidal
at Pillar Point, a headlands promontory to the west of Pillar Point
Harbor in San Mateo County, California, USA. Pillar Point is a popular
recreational intertidal area that is directly adjacent to the Pillar
Point State Marine Conservation Area (no specific use scientific
collection permit required).
Within Pillar Point, we sampled at three discrete locations: two
individual tide pools with a range of physical connectivity (Tide Pool
1, S1: 37.495306°, -122.498744°; Tide Pool 2, S2: 37.494992°,
-122.498955°) and an equidistant location (Nearshore, N: 37.495288°,
-122.499198°) where there was well-mixed offshore water for the duration
of the tidal cycle (Figure 2; not produced in R). Each site was
approximately 40 meters from all other sites. Tide Pool 1 and Tide Pool
2 are fully isolated at tidal heights of around 0 m (mean low low water,
MLLW) or lower, and substantially connected at around 0.25 m or higher.
On the day we sampled, this meant water actively flowed between the
locations at the start (11:30 PST) and end (17:00 PST) of the sampling
period, but that the sites were disconnected at low tide in the middle
of the sampling period. Ecologically, Tide Pool 1 was located closer to
shore and interior to a channel that divides the Pillar Point
intertidal, characteristic of the high to middle intertidal. Tide Pool 2
was located across the channel and further from shore, characteristic of
the low intertidal.
2.3 Sample Collection & Filtration
We collected 1 L surface samples from each site every 30 minutes for
the duration of time the rocky intertidal was exposed on 28 January
2022, using single-use enteral feeding pouches (Covidien, Dublin,
Ireland). The sampling volume used, 1 L, has been shown to be sufficient
for detecting a representative range of marine organisms in nearshore
locations (Gold et al., 2022) and is commonly used in aquatic eDNA
studies (Takahashi et al., 2023). Sampling commenced at 11:30 PST; the
exact times of sample collection, in relation to the tide, are shown in
Figure 3. At each site, samples were collected from a consistent
position across time points. Following the approach used by Gold et
al. (2021b), we attached a sterile 0.22 \(\mu\)m pore size Sterivex cartridge
(MilliporeSigma, Burlington, MA, USA) to the tubing of each feeding
pouch, allowing samples to be immediately gravity filtered in the field.
While gravity filtering (1-2 hours per sample), samples were shaded with
an awning to prevent any degradation by sunlight (Andruszkiewicz et al.,
2017).One sample fell during gravity filtration, resulting in a missing
sample from S1 at 16:00 PST.
### Figure 3###
# Produce the top portion of Figure 3 from tide data
# Read Pillar Point NOAA/NOS/CO-OPs Tide Chart data file
Tides <- read.table(
"Data/28-Jan-2022-TideChart.txt",
header = TRUE,
sep = "",
dec = ".",
skip = 13
)
# Convert date format in table using lubridate
Tides$datetime <-
lubridate::ymd_hm(paste(Tides$Date, Tides$Time), tz = "US/Pacific")
# Set bounds of sampling period to highlight
xmin <- Tides$datetime[47]
xmax <- Tides$datetime[69]
ymin <- -.5
ymax <- .5
box_color <- "#C0C0C0"
# Create plot of full tidal cycle with sampling period highlighted
p1 <- ggplot(data = Tides, aes(x = datetime, y = Pred, group = 1)) +
annotate(
"rect",
xmin = xmin,
xmax = xmax,
ymin = ymin,
ymax = ymax,
fill = box_color
) +
geom_line() +
coord_cartesian(xlim = c(Tides$datetime[1], Tides$datetime[96])) +
theme_classic(base_size = 12) +
theme(
panel.background = element_rect(fill = "transparent", colour = NA_character_),
# necessary to avoid drawing panel outline
plot.background = element_rect(fill = "transparent", colour = NA_character_),
# necessary to avoid drawing plot outline
axis.text.x = element_text(color = "black"),
axis.ticks = element_line(color = "black"),
axis.text.y = element_text(color = "black"),
panel.border = element_rect(
colour = "black",
fill = NA,
linewidth = 1
)
) +
xlab("Time (PST)") +
ylab("MLLW Tide Prediction (m)") +
scale_x_datetime(
date_breaks = "2 hour",
date_labels = "%H:00",
expand = c(0, 0),
position = "top"
)
# Create plot of just sampling period
p2 <- ggplot(data = Tides, aes(x = datetime, y = Pred, group = 1)) +
geom_line() +
coord_cartesian(xlim = c(xmin, xmax), ylim = c(ymin, ymax)) +
theme_classic(base_size = 12) +
theme(
panel.background = element_rect(fill = box_color),
plot.background = element_rect(fill = "transparent", colour = NA_character_),
axis.text.x = element_text(color = "black"),
axis.ticks = element_line(color = "black"),
axis.text.y = element_text(color = "black"),
panel.border = element_rect(
colour = "black",
fill = NA,
linewidth = 1
)
) +
theme(axis.title.x = element_blank()) +
ylab("MLLW Tide Prediction (m)") +
scale_x_datetime(
date_breaks = "30 min",
date_labels = "%H:%M",
expand = c(0, 0)
) +
theme(plot.margin = margin(b = 0))
# Stitch plots together using patchwork
p_patch <-
p1 / (p2 &
theme(plot.margin = ggplot2::margin(0, 0, 0, 0, "pt"))) &
ylab(NULL) &
theme(plot.background = element_rect(fill = "transparent", colour = NA_character_))
# Use the tag label as a y-axis label
p_patch <- wrap_elements(p_patch) +
labs(tag = "MLLW Tide Prediction (m)") +
theme(
plot.tag = element_text(size = rel(1.2), angle = 90),
plot.tag.position = "left",
plot.background = element_rect(fill = "transparent", colour = NA_character_)
)
if (!dir.exists("Figures")) {
dir.create("Figures")
}
path <- "Figures/Figure3."
save_pdf_png(
plot = p_patch,
path = path,
w = 169,
h = 90,
u = "mm",
bg = "transparent",
dpi = 600
)
First component of Figure 3 (second section
added once data has been loaded
At three time points (see full Figure 3, finalized below) at the
beginning and end of the sampling period as well as at low tide (at
14:00 PST), we collected triplicate 1 L samples from each location as
biological replicates. At the beginning and end of the sampling period,
we also filtered 1 L MilliQ water via the procedure described above to
serve as negative field controls. Additionally, using an Orion Model
1230 meter (Orion Research Inc., Beverly, MA, USA), we recorded
temperature and salinity in each location directly after samples were
collected.
Once finished filtering, Sterivex cartridges were dried by pushing
air through them using a sterile 3 mL syringe, capped, placed in sterile
Whirl-Pak bags (Whirl-Pak, Madison, WI, USA). Then, samples were stored
in a cooler on ice until transported back to the laboratory at the end
of the sampling period. Samples were transferred to a -20°C freezer for
up to 18 days, at which time they were processed to extract nucleic
acids from the captured materials. This sampling scheme resulted in 53
field samples.
2.5 Bioinformatics
We processed sequencing data using the Anacapa Toolkit, which
contains two core modules: one for quality control and ASV parsing, and
one for classifying taxonomy (Curd et al., 2019). Briefly, we ran the
first module using default parameters, which uses cutadapt (version
1.16) (Martin, 2011) for adapter and primer trimming, FastX-Toolkit
(version: 0.0.13) (citation) for quality trimming, and dada2 (version
1.6) (Callahan et al., 2016) for assigning ASVs. For the second module,
we utilized the MIDORI2 reference database, a quality controlled and
updated database built from GenBank release 253 (20 December 2022) that
has been technically validated (Leray et al., 2022). Following Gold et
al. (2022), we adjusted the identity and query coverage to 95% (default:
80%) to account for the relative incompleteness of the broad COI
reference database compared to more taxonomically-specific databases
(Curd et al., 2019). The second module relies on Bowtie 2 (version
2.3.5) (Langmead and Salzberg, 2012) and a modified instance of BLCA
(Gao et al., 2017) as dependencies. Following Gold et al. (2021a) we
only kept taxonomic assignments that had a bootstrap confidence cutoff
score of 60 or higher in BLCA, to avoid spurious assignments from the
incomplete reference database. We modified the Anacapa Container (Ogden,
2018), a Singularity container with all the needed dependencies for
executing the Anacapa Toolkit, to enable the pipeline to be run in a
high-performance computing environment requiring two-step
authentication; the updated container, scripts, and reference database
with the required Bowtie 2 index library needed to reproduce our
bioinformatics process can be found on Dryad (link/citation).
Raw ASVs, taxonomy assignments, and metadata were converted into
interchangeable ampvis2 (version 2.8.6
packageVersion("ampvis2")) (Andersen et al., 2018) and
phyloseq (version 1.46.0
packageVersion("phyloseq")) (McMurdie and Holmes, 2013)
objects in R version 4.3.1 (2023-06-16)
R.Version()$version.string to facilitate decontamination
and further analyses. Singletons were removed using
ampvis2, and samples were further decontaminated using
phyloseq by removing all ASVs that appeared in any negative
field control, negative extraction control, or no-template negative PCR
control, a choice made due to the very low number of overlapping ASVs
between samples and negative controls (Table S1). Samples were rarified
to the minimum number of reads of any sample using ampvis2.
Subsequent analyses were robust to all three decontamination steps.
### Importing Anacapa###
# Read in Anacapa Pipeline Output and process into ampvis2 objects for use in analyses
# Read in Anacapa Output
# Change p_confidence to switch to a different percent confidence output
###
p_confidence <- 60
###
current_subfolder <- "Data/Anacapa Pipeline Output/Tide Pool 5184 - 31 January 2023"
filepath <- paste0(
current_subfolder,
"/CO1/CO1_taxonomy_tables/Summary_by_percent_confidence/",
p_confidence,
"/CO1_ASV_raw_taxonomy_",
p_confidence,
".txt"
)
AnacapaOutput <- read.table(filepath,
header = TRUE,
sep = "\t",
dec = "."
)
# Format ASV Table (extract just the needed information)
endcol <- ncol(AnacapaOutput) - 1
asvmat <- AnacapaOutput[, 2:endcol]
rownames(asvmat) <- AnacapaOutput[, 1]
# Format Taxonomy Table (extract just the needed information and rename columns)
endcol <- ncol(AnacapaOutput)
taxmat <- AnacapaOutput[, endcol]
taxmat <- str_split_fixed(taxmat, ";", 7)
colnames(taxmat) <-
c(
"Kingdom",
"Phylum",
"Class",
"Order",
"Family",
"Genus",
"Species"
)
rownames(taxmat) <- rownames(asvmat)
# Read Metadata (saved in multiple different files)
current_subfolder <- paste0(
current_subfolder,
"/Metadata-Added/PillarPoint_SampleInfo_"
)
filepath <- paste0(current_subfolder, "EnviroData.txt")
EnviroData <- read.table(
filepath,
header = TRUE,
sep = "\t",
dec = ".",
strip.white = TRUE
)
filepath <- paste0(current_subfolder, "FieldSampling.txt")
FieldSampling <- read.table(
filepath,
header = TRUE,
sep = "\t",
dec = ".",
strip.white = TRUE
)
FieldSampling <- FieldSampling[, 1:4]
filepath <- paste0(current_subfolder, "Sequencing.txt")
Sequencing <- read.table(
filepath,
header = TRUE,
sep = "\t",
dec = ".",
strip.white = TRUE
)
filepath <- paste0(current_subfolder, "Location.txt")
Location <- read.table(
filepath,
header = TRUE,
sep = "\t",
dec = ".",
strip.white = TRUE
)
# Format Metadata
sampledata <- merge(FieldSampling, EnviroData, all = T)
sampledata <- sampledata %>% drop_na(Dereplicated_Sample_Name)
# removing one sample that has EnviroData reading but the field sample was not processed
sampledata <- merge(Sequencing, sampledata, all = T)
rownames(sampledata) <- sampledata[, "X"]
sampledata$Dereplicated_Sample_Name <- as.factor(sampledata$Dereplicated_Sample_Name)
sampledata$Type <- as.factor(sampledata$Type)
sampledata$PCR <- as.factor(sampledata$PCR)
sampledata$Time <- as.factor(sampledata$Time)
sampledata$Location <- as.factor(sampledata$Location)
sampledata$Extraction <- as.factor(sampledata$Extraction)
sampledata$SiteByTime <- as.factor(paste(sampledata$Location, sampledata$Time))
# Make ampvis2 objects without any pre-processing
asvmat_amp <- tibble::rownames_to_column(asvmat, "ASV")
sampledata_amp <- tibble::rownames_to_column(sampledata, "Sample")
taxmat_amp <- tibble::rownames_to_column(as.data.frame(taxmat), "ASV")
amp <- amp_load(asvmat_amp, metadata = sampledata_amp, taxonomy = taxmat_amp)
amp_nocontrols <- amp_filter_samples(amp, Type %in% c("sample"))
## 22 samples and 3315 OTUs have been filtered
## Before: 181 samples and 71947 OTUs
## After: 159 samples and 68632 OTUs
amp_controls <- amp_filter_samples(amp, Type %in% c("control"))
## 159 samples and 68607 OTUs have been filtered
## Before: 181 samples and 71947 OTUs
## After: 22 samples and 3340 OTUs
# Make ampvis2 objects with singletons removed
amp_NS <- amp_load(
asvmat_amp,
metadata = sampledata_amp,
taxonomy = taxmat_amp,
pruneSingletons = TRUE
)
## 41532 singletons have been removed
amp_nocontrols_NS <- amp_filter_samples(amp_NS, Type %in% c("sample"))
## 22 samples and 381 OTUs have been filtered
## Before: 181 samples and 30415 OTUs
## After: 159 samples and 30034 OTUs
amp_controls_NS <- amp_filter_samples(amp_NS, Type %in% c("control"))
## 159 samples and 30009 OTUs have been filtered
## Before: 181 samples and 30415 OTUs
## After: 22 samples and 406 OTUs
# Make ampvis2 objects with a full decontamination procedure
# Function that removes any ASV that appears in any control from all samples
full_decontamination <- function(amp) {
physeq <- amp_to_phyloseq(amp, NULL, NULL, NULL)
physeq_controls <- physeq %>%
subset_samples(Type == "control") %>%
prune_taxa(taxa_sums(.) > 0, .)
badASV <- taxa_names(physeq_controls)
allASV <- taxa_names(physeq)
allASV <- allASV[!(allASV %in% badASV)]
physeq_FD <- prune_taxa(allASV, physeq)
av2_otutable <- data.frame(otu_table(physeq_FD)@.Data)
av2_taxtable <- data.frame(tax_table(physeq_FD)@.Data)
av2_metadata <- data.frame(sample_data(physeq_FD))
amp_return <-
amp_load(av2_otutable, metadata = av2_metadata, taxonomy = av2_taxtable)
amp_return <- amp_filter_samples(amp_return, Type %in% c("sample"))
return(amp_return)
}
amp_nocontrols_FD <- full_decontamination(amp)
## 22 samples and 0 OTUs have been filtered
## Before: 181 samples and 68607 OTUs
## After: 159 samples and 68607 OTUs
amp_nocontrols_NS_FD <- full_decontamination(amp_NS)
## 22 samples and 0 OTUs have been filtered
## Before: 181 samples and 30009 OTUs
## After: 159 samples and 30009 OTUs
# Make ampvis2 objects by rarefying to the minimum number of reads of any sample
# Function that wraps around an ampvis2 function to rarefy samples to the minimum number of reads of any sample
rarefaction <- function(amp) {
set.seed(0)
reads <- colSums(amp$abund)
minreads <- min(reads)
amp_R <- amp_subset_samples(amp, rarefy = minreads)
return(amp_R)
}
amp_nocontrols_R <- rarefaction(amp_nocontrols)
## 0 samples have been filtered.
amp_nocontrols_NS_R <- rarefaction(amp_nocontrols_NS)
## 0 samples have been filtered.
amp_nocontrols_FD_R <- rarefaction(amp_nocontrols_FD)
## 0 samples have been filtered.
amp_nocontrols_NS_FD_R <- rarefaction(amp_nocontrols_NS_FD)
## 0 samples have been filtered.
### Making NCBI Data Frames###
## Create data frames for submission to NCBI SRA based on required information in BioSample package MIMARKS: survey, water; version 6.0 as well as additional suggested detailed from the NOAA Omics Data Management Guide (https://noaa-omics-dmg.readthedocs.io/en/latest/contributors.html)
## BioSample attributes
NCBI_export <- merge(amp$metadata, Location, all = T)
# Latitude + Longitude
lat_lon <- do.call(paste, list(
NCBI_export$Latitude,
"N",
gsub("-", "", NCBI_export$Longitude),
"W",
sep = " "
))
lat_lon[lat_lon == "NA N NA W"] <- "NA"
NCBI_export <- cbind(NCBI_export, lat_lon)
# Date and time
Date <- "2022-01-28"
NCBI_export <- cbind(NCBI_export, Date)
NCBI_export$collection_date_local <-
lubridate::ymd_hm(paste(NCBI_export$Date, "T", NCBI_export$Time), tz = "US/Pacific")
NCBI_export$collection_date <-
with_tz(NCBI_export$collection_date_local, "Zulu")
Zulu <- stamp("2020-04-04T18:05:00Z")
## Multiple formats matched: "%Y-%Om-%dT%H:%M:%S%Ou"(1), "%Y-%Om-%dT%H:%M:%SZ"(1), "%Y-%d-%OmT%H:%M:%SZ"(1), "%Y-%m-%dT%H:%M:%S%Ou"(1), "%Y-%m-%dT%H:%M:%SZ"(1), "%Y-%d-%mT%H:%M:%SZ"(1)
## Using: "%Y-%Om-%dT%H:%M:%S%Ou"
NCBI_export$collection_date <- Zulu(NCBI_export$collection_date)
PST <- stamp("2020-04-04T18:05:00PST")
## Multiple formats matched: "%Y-%Om-%dT%H:%M:%SPST"(1), "%Y-%d-%OmT%H:%M:%SPST"(1), "%Y-%m-%dT%H:%M:%SPST"(1), "%Y-%d-%mT%H:%M:%SPST"(1)
## Using: "%Y-%Om-%dT%H:%M:%SPST"
NCBI_export$collection_date_local <- PST(NCBI_export$collection_date_local)
# Rename columns
NCBI_export <- NCBI_export[c(
"Sample",
"Sample_Name",
"Type",
"Location",
"T",
"S",
"CRS",
"lat_lon",
"collection_date",
"collection_date_local"
)]
NCBI_export <- NCBI_export %>% rename(
sample_name = Sample,
sample_title = Sample_Name,
sample_control = Type,
salinity = S,
temperature = T,
geodeticDatum = CRS
)
NCBI_export$unique_sample_identifier <- NCBI_export$sample_title
# Add units to temperature & salinity
NCBI_export$temperature[!is.na(NCBI_export$temperature)] <- paste(NCBI_export$temperature[!is.na(NCBI_export$temperature)], "°C", sep = " ")
NCBI_export$salinity[!is.na(NCBI_export$salinity)] <- paste(NCBI_export$salinity[!is.na(NCBI_export$salinity)], "ppt", sep = " ")
# Depth
depth <- c()
depth[NCBI_export$sample_control == "control"] <- "NA"
depth[NCBI_export$sample_control == "sample"] <- "Surface"
NCBI_export <- cbind(NCBI_export, depth)
# Size fraction
size_frac <- c()
size_frac[NCBI_export$sample_control == "control"] <- "NA"
size_frac[NCBI_export$sample_control == "sample"] <- "0.22 micrometer"
size_frac[NCBI_export$Location == "FB"] <- "0.22 micrometer"
NCBI_export <- cbind(NCBI_export, size_frac)
# Sample volume
samp_vol_we_dna_ext <- c()
samp_vol_we_dna_ext[NCBI_export$sample_control == "control"] <- "NA"
samp_vol_we_dna_ext[NCBI_export$sample_control == "sample"] <- "1000 mL"
samp_vol_we_dna_ext[NCBI_export$Location == "FB"] <- "1000 mL"
NCBI_export <- cbind(NCBI_export, samp_vol_we_dna_ext)
# Organism
organism <- c()
organism[NCBI_export$sample_control == "sample"] <- "seawater metagenome"
organism[NCBI_export$Location == "MC"] <- "synthetic metagenome"
organism[NCBI_export$Location == "EB"] <- "metagenome"
organism[NCBI_export$Location == "FB"] <- "metagenome"
organism[NCBI_export$Location == "NTC"] <- "metagenome"
NCBI_export <- cbind(NCBI_export, organism)
# Environmental Context
env_broad_scale <- c()
env_broad_scale[NCBI_export$sample_control == "sample"] <- "marine biome [ENVO:00000447]"
NCBI_export <- cbind(NCBI_export, env_broad_scale)
env_local_scale <- c()
env_local_scale[NCBI_export$sample_control == "sample"] <- "shoreline [ENVO:00000486]|intertidal zone [ENVO:00000316]"
NCBI_export <- cbind(NCBI_export, env_local_scale)
env_medium <- c()
env_medium[NCBI_export$sample_control == "sample"] <- "coastal sea water [ENVO_00002150]"
NCBI_export <- cbind(NCBI_export, env_medium)
geo_loc_name <- c()
geo_loc_name[NCBI_export$sample_control == "sample"] <- "USA: California, Half Moon Bay, Pillar Point, Intertidal"
NCBI_export <- cbind(NCBI_export, geo_loc_name)
# Sampling Methods
samp_mat_process <- c()
samp_mat_process[NCBI_export$sample_control == "sample"] <- "Gravity filtered through Sterivex (0.22-µm): dx.doi.org/10.17504/protocols.io.bp2l69y7klqe/v2"
samp_mat_process[NCBI_export$Location == "MC"] <- "Mock community from equimolar combination of 5 tisue DNA extraction: Mytilus edulis, Mizuhopecten yessoensis, Xiphias gladius, Mercenaria mercenaria, Lutjanus campechanus"
samp_mat_process[NCBI_export$Location == "EB"] <- "DNA extraction from a sterile Sterivex: dx.doi.org/10.17504/protocols.io.ewov1qyyygr2/v1"
samp_mat_process[NCBI_export$Location == "FB"] <- "Gravity filtered through Sterivex (0.22-µm): dx.doi.org/10.17504/protocols.io.bp2l69y7klqe/v2"
samp_mat_process[NCBI_export$Location == "NTC"] <- "PCR no-template control for first PCR reaction: dx.doi.org/10.17504/protocols.io.dm6gp3wpdvzp/v1"
NCBI_export <- cbind(NCBI_export, samp_mat_process)
samp_collect_device <- c()
samp_collect_device[NCBI_export$sample_control == "sample"] <- "Covidien single-use enteral feeding pouch"
samp_collect_device[NCBI_export$Location == "FB"] <- "Covidien single-use enteral feeding pouch"
NCBI_export <- cbind(NCBI_export, samp_collect_device)
amplicon_sequenced <- "COI"
NCBI_export <- cbind(NCBI_export, amplicon_sequenced)
NCBI_export$sample_title[NCBI_export$sample_control == "sample"] <- paste("Pillar Point intertidal seawater sample", NCBI_export$sample_title[NCBI_export$sample_control == "sample"], sep = " ")
NCBI_export$sample_title[NCBI_export$Location == "EB"] <- paste("Extraction blank", NCBI_export$sample_title[NCBI_export$Location == "EB"], sep = " ")
NCBI_export$sample_title[NCBI_export$Location == "FB"] <- paste("MilliQ water field blank", NCBI_export$sample_title[NCBI_export$Location == "FB"], sep = " ")
NCBI_export$sample_title[NCBI_export$Location == "NTC"] <- paste("PCR no-template control", NCBI_export$sample_title[NCBI_export$Location == "NTC"], sep = " ")
NCBI_export$sample_title[NCBI_export$Location == "MC"] <- paste("Custom mock community sample", NCBI_export$sample_title[NCBI_export$Location == "MC"], sep = " ")
# Sample Storage
sample_storage_duration <- c()
sample_storage_duration[NCBI_export$sample_control == "sample"] <- "18 days"
sample_storage_duration[NCBI_export$Location == "FB"] <- "18 days"
NCBI_export <- cbind(NCBI_export, sample_storage_duration)
sample_storage_location <- c()
sample_storage_location[NCBI_export$sample_control == "sample"] <- "Stanford Y2E2 Building, Environmental Engineering and Science Lab, Walk-In -20 °C Freezer"
sample_storage_location[NCBI_export$Location == "FB"] <- "Stanford Y2E2 Building, Environmental Engineering and Science Lab, Walk-In -20 °C Freezer"
NCBI_export <- cbind(NCBI_export, sample_storage_location)
sample_storage_temperature <- c()
sample_storage_temperature[NCBI_export$sample_control == "sample"] <- "-20 °C"
sample_storage_temperature[NCBI_export$Location == "FB"] <- "-20 °C"
NCBI_export <- cbind(NCBI_export, sample_storage_temperature)
NCBI_export <- NCBI_export %>% rename(specific_intertidal_location = Location)
NCBI_export$specific_intertidal_location <- as.character(NCBI_export$specific_intertidal_location)
NCBI_export$specific_intertidal_location[NCBI_export$sample_control == "control"] <- "NA"
NCBI_export[is.na(NCBI_export)] <- "not applicable"
NCBI_export[NCBI_export == "NA"] <- "not applicable"
## SRA Metadata
SRA_metadata <- NCBI_export[c("sample_name", "unique_sample_identifier")]
SRA_metadata <- SRA_metadata %>% rename(library_ID = unique_sample_identifier)
SRA_metadata$title <- "COI amplicon metabarcoding of seawater for marine metazoa: Pillar Point, Half Moon Bay, CA (USA)"
SRA_metadata$library_strategy <- "AMPLICON"
SRA_metadata$library_source <- "METAGENOMIC"
SRA_metadata$library_selection <- "PCR"
SRA_metadata$library_layout <- "paired"
SRA_metadata$platform <- "ILLUMINA"
SRA_metadata$instrument_model <- "Illumina MiSeq"
SRA_metadata$design_description <- "Water samples were gravity filtered onto Sterivex 0.22 µm filter cartridges (dx.doi.org/10.17504/protocols.io.bp2l69y7klqe/v2). DNA was extracted using a modified version of the DNeasy Blood and Tissue Kit (Qiagen, Germantown, MD, USA), in methods described here (dx.doi.org/10.17504/protocols.io.ewov1qyyygr2/v1). Samples were PCR amplified using the mlCOIintF/ jgHCO2198 primer set targeting a 313 bp fragment of the mitochondrial COI region optimized by Leray et al. (2013) (Forward: GGWACWGGWTGAACWGTWTAYCCYCC; Reverse: TAIACYTCIGGRTGICCRAARAAYCA) with Nextera modifications. Full PCR methods can be found here (dx.doi.org/10.17504/protocols.io.dm6gp3wpdvzp/v1). PCR products were sent for library preparation and sequencing at the Georgia Genomics and Bioinformatics Core (GGBC, UG Athens, GA, RRID:SCR_010994). In short, provided PCR amplicons were cleaned using AMPure XP magnetic beads (Beckman Coulter, Indianapolis, IN, USA), barcoded with Nextera adapters (Illumina, San Diego, CA, USA) during a second PCR (3 min at 95 °C; 15 cycles of 30 sec at 95 °C, 30 sec at 67 °C, and 30 sec at 72 °C; and 4 min at 72 °C), cleaned again using AMPureXP magnetic beads, and pooled in equimolar ratio. The resulting library was sequenced on a MiSeq PE 2x250bp (500 cycles) using Reagent Kit V2 with 25% PhiX spike-in (Illumina, San Diego, CA, USA)."
SRA_metadata$filetype <- "fastq"
filename <- gsub(".*_", "", SRA_metadata$sample_name)
filename <- sub("\\.L001", "_L001", filename)
filename <- sub("\\.S", "_S", filename)
filename <- gsub("\\.", "-", filename)
SRA_metadata$filename <- paste0(filename, "_R1_001.fastq.gz")
SRA_metadata$filename2 <- paste0(filename, "_R2_001.fastq.gz")
if (!dir.exists("Analysis Products/Processed eDNA/NCBI")) {
dir.create("Analysis Products/Processed eDNA/NCBI", recursive = TRUE)
}
write.csv(
NCBI_export,
"Analysis Products/Processed eDNA/NCBI/BioSample_Attributes.csv",
row.names = FALSE
)
write.csv(SRA_metadata,
"Analysis Products/Processed eDNA/NCBI/SRA_metadata.csv",
row.names = FALSE
)
### Making GBIF Data Frames###
## Create data frames for submission to GBIF through the beta eDNA data converter (https://edna-tool.gbif-uat.org/)
# Export version of data with decontamination and controls removed but no additional processing
# Make defaultValues data frame for variables that are the same for all samples
defaultValues <- as.data.frame(matrix(ncol = 2, nrow = 0))
colnames(defaultValues) <- c("term", "value")
defaultValues <- as_tibble(defaultValues) %>% mutate(term = as.character(term), value = as.character(value))
defaultValues <- defaultValues %>%
add_row(term = "env_medium", value = "coastal sea water [ENVO_00002150]") %>%
add_row(term = "env_broad_scale", value = "marine biome [ENVO:00000447]") %>%
add_row(term = "env_local_scale", value = "shoreline [ENVO:00000486]|intertidal zone [ENVO:00000316]") %>%
add_row(term = "project_name", value = "Environmental DNA metabarcoding differentiates between micro-habitats within the rocky intertidal") %>%
add_row(term = "target_gene", value = "COI") %>%
add_row(term = "pcr_primer_forward", value = "GGWACWGGWTGAACWGTWTAYCCYCC") %>%
add_row(term = "pcr_primer_name_forward", value = "mlCOIintF") %>%
add_row(term = "pcr_primer_reverse", value = "TAIACYTCIGGRTGICCRAARAAYCA") %>%
add_row(term = "pcr_primer_name_reverse", value = "jgHCO2198") %>%
add_row(term = "sop", value = "https://www.biorxiv.org/content/10.1101/2023.08.03.551543v1") %>%
add_row(term = "seq_meth", value = "Illumina MiSeq") %>%
add_row(term = "samplingProtocol", value = "https://dx.doi.org/10.17504/protocols.io.bp2l69y7klqe/v2") %>%
add_row(term = "size_frac", value = "0.22 micrometer") %>%
add_row(term = "samp_vol_we_dna_ext", value = "1000 mL") %>%
add_row(term = "samp_collec_device", value = "Covidien single-use enteral feeding pouch") %>%
add_row(term = "samp_collec_method", value = "Covidien single-use enteral feeding pouch: https://dx.doi.org/10.17504/protocols.io.bp2l69y7klqe/v2") %>%
add_row(term = "samp_mat_process", value = "Gravity filtered through Sterivex (0.22-µm): https://dx.doi.org/10.17504/protocols.io.bp2l69y7klqe/v2") %>%
add_row(term = "annealingTemp", value = "69.5") %>%
add_row(term = "annealingTempUnit", value = "Degrees Celsius") %>%
add_row(term = "ampliconSize", value = "313") %>%
add_row(term = "amplificationReactionVolume", value = "25") %>%
add_row(term = "amplicationReactionVolumeUnit", value = "µl") %>%
add_row(term = "nucl_acid_ext", value = "https://dx.doi.org/10.17504/protocols.io.ewov1qyyygr2/v1") %>%
add_row(term = "nucl_acid_amp", value = "https://dx.doi.org/10.17504/protocols.io.dm6gp3wpdvzp/v1") %>%
add_row(term = "lib_layout", value = "paired") %>%
add_row(term = "verbatimDepth", value = "Surface") %>%
add_row(term = "basisOfRecord", value = "Material sample") %>%
add_row(term = "institutionID", value = "https://ror.org/00f54p054") %>%
add_row(term = "institutionCode", value = "Stanford University") %>%
add_row(term = "organismQuantityType", value = "DNA sequence reads") %>%
add_row(term = "otu_db", value = "MIDORI2 reference database,v. GB253 (20 December 2022): https://www.reference-midori.info/download.php")
# Make taxa, samples, and OTU table files
GBIF_export <- amp_nocontrols_FD
GBIF_export$metadata <- merge(GBIF_export$metadata, Location, all = T)
GBIF_export$tax$Kingdom <- remove_NCBInums(GBIF_export$tax$Kingdom)
GBIF_export$tax$Phylum <- remove_NCBInums(GBIF_export$tax$Phylum)
GBIF_export$tax$Class <- remove_NCBInums(GBIF_export$tax$Class)
GBIF_export$tax$Order <- remove_NCBInums(GBIF_export$tax$Order)
GBIF_export$tax$Family <- remove_NCBInums(GBIF_export$tax$Family)
GBIF_export$tax$Genus <- remove_NCBInums(GBIF_export$tax$Genus)
GBIF_export$tax$Species <- remove_NCBInums(GBIF_export$tax$Species)
# Add date + time
Date <- "2022-01-28"
GBIF_export$metadata <- cbind(GBIF_export$metadata, Date)
GBIF_export$metadata$verbatimEventDate <-
lubridate::ymd_hm(paste(GBIF_export$metadata$Date, "T", GBIF_export$metadata$Time),
tz = "US/Pacific"
)
GBIF_export$metadata$eventDate <-
with_tz(GBIF_export$metadata$verbatimEventDate, "Zulu")
Zulu <- stamp("2020-04-04T18:05:00Z")
## Multiple formats matched: "%Y-%Om-%dT%H:%M:%S%Ou"(1), "%Y-%Om-%dT%H:%M:%SZ"(1), "%Y-%d-%OmT%H:%M:%SZ"(1), "%Y-%m-%dT%H:%M:%S%Ou"(1), "%Y-%m-%dT%H:%M:%SZ"(1), "%Y-%d-%mT%H:%M:%SZ"(1)
## Using: "%Y-%Om-%dT%H:%M:%S%Ou"
GBIF_export$metadata$eventDate <- Zulu(GBIF_export$metadata$eventDate)
PST <- stamp("2020-04-04T18:05:00PST")
## Multiple formats matched: "%Y-%Om-%dT%H:%M:%SPST"(1), "%Y-%d-%OmT%H:%M:%SPST"(1), "%Y-%m-%dT%H:%M:%SPST"(1), "%Y-%d-%mT%H:%M:%SPST"(1)
## Using: "%Y-%Om-%dT%H:%M:%SPST"
GBIF_export$metadata$verbatimEventDate <- PST(GBIF_export$metadata$verbatimEventDate)
names(GBIF_export$metadata)[names(GBIF_export$metadata) == "Sample"] <-
"id"
col_order <- c(
"id",
"Sample_Name",
"Location",
"Latitude",
"Longitude",
"CRS",
"eventDate",
"verbatimEventDate",
"T",
"S"
)
GBIF_export$metadata <- GBIF_export$metadata[, col_order]
# If you have SRA metadata records from successful NCBI submission, process them here
if (dir.exists("Analysis Products/Processed eDNA/NCBI/NCBI Upload Record")) {
SRA <- read.delim(
"Analysis Products/Processed eDNA/NCBI/NCBI Upload Record/metadata-14288727-processed-ok.tsv",
sep = "\t"
)
SRA <- SRA[c("accession", "biosample_accession", "sample_name")]
SRA$biosample_accession <- paste0(
"https://www.ncbi.nlm.nih.gov/biosample/?term=",
SRA$biosample_accession
)
SRA$accession <- paste0("https://www.ncbi.nlm.nih.gov/sra/?term=", SRA$accession)
GBIF_export$metadata <- left_join(GBIF_export$metadata, SRA, by = join_by(id == sample_name))
}
GBIF_export$metadata <- GBIF_export$metadata %>% rename(
associatedSequences = accession,
materialSampleID = biosample_accession,
temperature = T,
salinity = S
)
# Add sequences to file
current_subfolder <- "Data/Anacapa Pipeline Output/Tide Pool 5184 - 31 January 2023"
filepath <- paste0(
current_subfolder,
"/CO1/CO1_taxonomy_tables/CO1_ASV_taxonomy_detailed.txt"
)
AnacapaDetailed <- read.table(filepath,
header = TRUE,
sep = "\t",
dec = "."
)
sequences <- as.data.frame(AnacapaDetailed[, c("sequence", "sequencesF", "sequencesR")])
sequences$sequence_unmerged <- paste0(
"[UNMERGED SEQUENCE COMBINATION] F: ",
sequences$sequencesF,
"; R: ",
sequences$sequencesR
)
sequences <-
sequences %>% mutate(sequence = ifelse(sequence == "", sequence_unmerged, sequence))
rownames(sequences) <- AnacapaDetailed$CO1_seq_number
GBIF_export$tax <- merge(
sequences,
GBIF_export$tax,
by = "row.names",
all.x = FALSE,
all.y = TRUE,
sort = FALSE
)
rownames(GBIF_export$tax) <- GBIF_export$tax$Row.names
col_order <- c(
"sequence",
"Kingdom",
"Phylum",
"Class",
"Order",
"Family",
"Genus",
"Species"
)
GBIF_export$tax <- GBIF_export$tax[, col_order]
if (!dir.exists("Analysis Products/Processed eDNA/GBIF")) {
dir.create("Analysis Products/Processed eDNA/GBIF", recursive = TRUE)
}
write.csv(
GBIF_export$abund,
"Analysis Products/Processed eDNA/GBIF/OTUtable.csv",
row.names = TRUE
)
write.csv(
GBIF_export$tax,
"Analysis Products/Processed eDNA/GBIF/taxa.csv",
row.names = TRUE
)
write.csv(
GBIF_export$metadata,
"Analysis Products/Processed eDNA/GBIF/samples.csv",
row.names = FALSE
)
write.csv(
defaultValues,
"Analysis Products/Processed eDNA/GBIF/defaultValues.csv",
row.names = FALSE
)
To ensure the accuracy of taxonomic assignments, we analyzed
occurrence data from the Global Biodiversity Information Facility to
investigate whether identified species had occurrence records in the
California Current System and known ranges that encompassed Pillar
Point, using the spocc (version 1.2.2
packageVersion("spocc")) (Chamberlain, 2021) package. A
phylogenetic tree based on taxonomic assignments was created using the
taxize (version 0.9.100 packageVersion("taxize"))
(Chamberlain and Szöcs, 2013) and ggtreeExtra 1.12.0
packageVersion("ggtreeExtra") (citation) packages.
Data Analysis
To understand whether eDNA signals could be distinguished by
location, we first analyzed individual-level differences between
locations; that is, whether ASVs or individual taxa (agglomerated
species-level taxonomic assignments) were unique to, or associated with,
particular locations. We calculated and visualized unique ASVs and taxa
using the eulerr (version 7.0.0
packageVersion("eulerr")) (Larsson, 2022) package. However,
with metabarcoding data in particular, taxa or ASVs that are unique to a
given location are not necessarily ecologically meaningful; they could
include rare taxa present elsewhere but not amplified and exclude taxa
that are well correlated with particular locations but sometimes
detected at others. Thus, we also analyzed ASVs and taxa using an
indicator species framework (Dufrêne and Legendre, 1997). In this
framework, the null hypothesis is that the frequency of a taxon’s or
ASV’s presence in samples from a particular location is not higher that
the frequency of that taxon’s or ASV’s presence in samples from other
locations. For each location, we identified all
statistically-significant indicator taxa and ASVs with indicator value
indices above 0.7—that is, indicators that are well-associated with a
site group even if they are detected in samples from other sites—based
on presence-absence data per sample using the indicspecies
package (version 1.7.14 packageVersion("indicspecies"))
(Cáceres and Legendre, 2009).
We followed our individual-level analyses with approaches to test
whether community composition varied by location. We calculated a
Jaccard dissimilarity matrix across all samples using vegan
(version 2.6.4 packageVersion("vegan")) (Oksanen et al.,
2022). Then, we tested for differences in community composition among
locations using a permutational multivariate analysis of variance
(PERMANOVA) with the model eDNA Presence ~ Location + Time + Biological
Replicates using the adonis function in vegan.
We confirmed that locational differences found via PERMANOVA were not a
result of differences in dispersions by testing for homogeneity of
dispersions using the betadisper function in
vegan. We also visualized Jaccard dissimilarity using
non-metric multidimensional scaling (NMDS) using the
metaMDS function in vegan. We coupled these
analyses with a partitioning among medoids algorithm (Kaufman and
Rousseeuw, 1990) implemented with the pam function in the
cluster package (version 2.1.6
packageVersion("cluster")) (Maechler et al., 2022). Rather
than assuming location clusters a priori, we validated the optimal
number of clusters for a given dataset by finding the number of clusters
(k) that maximized the average silhouette width, a measure of how
well-structured the clusters are. Finally, to better understand how the
difference between locations varied over the time sampled, for each time
point, we calculated the Jaccard dissimilarity between each unique
combination of replicates within each site, and then the pairwise
Jaccard dissimilarity between each unique combination of samples across
the three pairs of sites: S1-N, S2-N, and S1-S2.
To further investigate whether differences in eDNA detections
corresponded with underlying ecological gradients, we compared the
unique and indicator taxa identified at each site to their ecological
zonation in a highly regarded field guide to the Pacific intertidal,
Between Pacific Tides (Ricketts et al., 1985). To account for potential
variations in taxonomic names between Between Pacific Tides and the
MIDORI2 reference database, we used the World Register of Marine Species
(WoRMS) to identify all synonymized names for each unique and indicator
taxon identified using the taxize (version 0.9.100
packageVersion("taxize")) (S. A. Chamberlain & Szöcs,
2013) package. Then, we searched Between Pacific Tides for all synonyms,
both manually using the index and in R by extracting the text from a PDF
of Between Pacific Tides using the pdftools package
(version 3.4.0 packageVersion("pdftools")) (Ooms, 2023). We
compared the proportion of Zone 1 (uppermost horizon), Zone 2 (high
intertidal), and Zone 3 (middle intertidal) species identified across
each location using a chi-squared test with p-values computed via Monte
Carlo simulation.
Results
3.1 Sequencing Results & Taxonomic Diversity
### Full Output Metrics###
# Generate information about the full Anacapa Pipeline results
# Gather information about full Anacapa Pipeline results before any processing
total_ASVs <- nrow(amp$abund)
total_reads <- sum(amp$abund)
samples <- length(amp$metadata$Type[amp$metadata$Type == "sample"])
controls <- length(amp$metadata$Type[amp$metadata$Type == "control"])
# Check positive PCR controls
amp_MC <- amp_filter_samples(amp, Location %in% c("MC"))
## 179 samples and 71797 OTUs have been filtered
## Before: 181 samples and 71947 OTUs
## After: 2 samples and 150 OTUs
df <- merge(amp_MC$abund, amp_MC$tax, by = "row.names")
df <- df[, c(2:3, 10)]
colnames(df) <- c("MC1", "MC2", "Species")
agg_df <-
df %>%
group_by(Species) %>%
summarise(MC1_Reads = sum(MC1), MC2_Reads = sum(MC2)) %>%
arrange(desc(MC1_Reads))
agg_df[agg_df == ""] <- "No Taxonomic Assignment"
agg_df$Species <- remove_NCBInums(agg_df$Species)
agg_df
amp_no_MC <- amp_filter_samples(amp, !(Location %in% c("MC")))
## 2 samples and 150 OTUs have been filtered
## Before: 181 samples and 71947 OTUs
## After: 179 samples and 71797 OTUs
if (length(intersect(rownames(amp_MC$abund), rownames(amp_no_MC$abund))) == 0) {
MC_overlap <- "no ASVs present in the positive PCR controls occurred in any other samples, providing no evidence of index hopping"
} else {
MC_overlap <- "some ASVs present in the positive PCR controls occurred in other samples, providing evidence of index hopping (CHECK THIS)"
}
# Check intersection between samples and controls
intersect <- intersect(
rownames(amp_controls$abund),
rownames(amp_nocontrols$abund)
)
overlap <- length(intersect)
overlap_table <- data.frame(
ASV = intersect,
"Taxonomic Assignment" = amp_nocontrols$tax[amp_nocontrols$tax$OTU %in% intersect, ]$Species
)
overlap_table$Taxonomic.Assignment <- remove_NCBInums(overlap_table$Taxonomic.Assignment)
overlap_table
Using the Anacapa Toolkit, we identified 71947
(total_ASVs) ASVs from 9291419(total_reads)
reads across 159 (samples) samples and 22
(controls) controls (positive PCR controls, negative field
controls, negative extraction controls, and no-template negative PCR
controls). All expected taxa amplified in each positive PCR control, and
no ASVs present in the positive PCR controls occurred in any other
samples, providing no evidence of index hopping
(MC_overlap). Before application of any decontamination
steps, only 25 (overlap) ASVs were shared between the
samples and negative field, extraction, and PCR controls.
### Core Data Sets###
# Establish processed data set used throughout analyses
data_amp <- amp_nocontrols_NS_FD_R
data_physeq <- amp_to_phyloseq(data_amp, NULL, NULL, NULL)
data_amp_taxa <- data_amp
data_amp_taxa$abund <- aggregate_abund(data_amp$abund,
data_amp$tax,
tax_aggregate = "Species",
format = "abund"
)
## 24191 OTUs (out of 27038) with no assigned taxonomy at Species level were removed before aggregating OTUs
if (!dir.exists("Analysis Products/Processed eDNA/Manuscript Analysis")) {
dir.create("Analysis Products/Processed eDNA/Manuscript Analysis",
recursive = TRUE
)
}
write.csv(
data_amp$abund,
"Analysis Products/Processed eDNA/Manuscript Analysis/ASVTable.csv",
row.names = TRUE
)
write.csv(
data_amp$tax,
"Analysis Products/Processed eDNA/Manuscript Analysis/TaxTable.csv",
row.names = TRUE
)
write.csv(
data_amp$metadata,
"Analysis Products/Processed eDNA/Manuscript Analysis/SampleData.csv",
row.names = FALSE
)
### Figure 3--Continued###
# Finish the bottom portion of Figure 3 now that data has been loaded
data_forchart <- amp$metadata[!is.na(amp$metadata$Time), ]
data_forchart <- data_forchart %>%
group_by(SiteByTime) %>%
mutate(chart_num = ceiling(row_number() / 3))
facet.labs <- c(
"Tide Pool 1\n (S1)",
"Tide Pool 2\n (S2)",
"Nearshore\n (N)",
"Field Blank"
)
names(facet.labs) <- c("S1", "S2", "N", "FB")
data_forchart$Location <- factor(data_forchart$Location, levels = c("S1", "S2", "N", "FB"))
data_forchart$chart_num <- factor(data_forchart$chart_num, levels = c("3", "2", "1"))
sample_schema <- ggplot(
data = data_forchart,
aes(
x = Time,
y = chart_num,
shape = Location,
color = Time,
fill = after_scale(alpha(colour, 0.05))
)
) +
geom_beeswarm(cex = 2, size = 3) +
geom_box(
aes(
xmin = after_stat(x) - 0.45,
xmax = after_stat(x) + 0.45,
ymin = after_stat(y) - 0.45,
ymax = after_stat(y) + 0.45
),
radius = unit(5, "pt")
) +
scale_shape_manual(values = c(15, 17, 16, 18)) +
scale_color_viridis_d(
direction = -1,
begin = 0,
end = .97
) +
facet_grid(
Location ~ .,
scales = "free_y",
space = "free_y",
switch = "y",
labeller = labeller(Location = facet.labs)
) +
theme_void(base_size = 12) +
theme(
legend.position = "none",
strip.text.y.left = element_text(
angle = 0,
hjust = 1,
vjust = .9
),
plot.margin = ggplot2::margin(0, 0, 0, 0, "pt")
) +
theme(axis.ticks.x = element_line(linewidth = .5)) +
theme(axis.ticks.length.x = unit(0.15, "cm")) +
scale_x_discrete(position = "top")
combined <- (plot_spacer() + p_patch + plot_spacer() + plot_layout(widths = c(3, 50, 1.2))) /
(plot_spacer()) / (plot_spacer() + sample_schema + plot_layout(widths = c(1, 50))) + plot_layout(heights = c(4, -.05, 5)) &
theme(plot.margin = ggplot2::margin(0, 0, 0, 0, "pt"))
path <- "Figures/Figure3_full."
save_pdf_png(
plot = combined,
path = path,
w = 169,
h = 169,
u = "mm",
bg = "transparent",
dpi = 600
)
Figure 3: Graph of tide predictions during
field sampling on 28 January 2022, with icons to indicate the sampling
scheme
### Processed Output Metrics###
# Gather information about processed Anacapa Toolkit
processed_ASVs <- nrow(data_amp$abund)
processed_reads <- sum(data_amp$abund)
# Create a phyloseq object where all samples are combined into one
total <- as.data.frame(rowSums(data_amp$abund))
physeq_summed <- amp_to_phyloseq(NULL, total, data_amp$tax[, 1:7], NULL)
# Summarize the number of unassigned ASVs
kingdom <- as.data.frame(tax_table(physeq_summed)[, 1])
unassigned_ASVs <- kingdom %>%
group_by(Kingdom) %>%
summarise(n = n()) %>%
mutate(freq = n / sum(n))
# Summarize number of unique taxa at each taxonomic level
unique <- apply(tax_table(physeq_summed), 2, function(x) {
length(unique(x[x != ""]))
})
### GBIF Set-Up###
# Create functions and datasets needed for GBIF analysis
# Create list of identified species
species_list <- unique(data_amp$tax$Species)
species_list <- remove_NCBInums(species_list)
species_list <- species_list[species_list != ""]
species_list <- sub("_", "-", species_list) # to address Pseudo_nitzchia error
# Standardize species names against GBIF backbone
species_GBIF <- name_backbone_checklist(species_list)
species_standardized <- species_GBIF$species[!is.na(species_GBIF$species)]
species_both <- species_GBIF[c("species", "verbatim_name")]
## Core GBIF checking function
distribution_check <-
function(small_bound,
big_bound,
species,
min_records,
efficiency) {
## Function that checks GBIF given a particular geographic region
boundary_function <- function(species, bounds) {
no_data <- c()
confirmed <- c()
for (i in species) {
print(i)
occ <- occ(
query = i,
geometry = bounds,
from = "gbif",
limit = min_records,
has_coords = TRUE,
gbifopts = list(hasGeospatialIssue = FALSE)
)
occ.df <- occ2df(occ)
if (nrow(occ.df) >= min_records) {
confirmed <- append(confirmed, i)
} else {
no_data <- append(no_data, i)
}
}
return(list(no_data = no_data, confirmed = confirmed))
}
## Function that checks GBIF to confirm whether a particular location is within the range of observations
range_function <- function(species) {
CC.confirmed <- c()
CC.not_confirmed <- c()
CC.no_data <- c()
limits <- c(10, 100, 1000, 10000)
for (i in species) {
track <- 0
for (l in limits) {
print(i)
print(l)
occ <- occ(
i,
from = "gbif",
limit = l,
has_coords = TRUE,
gbifopts = list(hasGeospatialIssue = FALSE)
)
occ.df <- occ2df(occ)
if (nrow(occ.df) < min_records) {
CC.no_data <- append(CC.no_data, i)
print("no data")
track <- 1
break
}
bb_occ <- sp::bbox(cbind(occ.df$longitude, occ.df$latitude))
if (bb_occ["x", "min"] < small_bound[1] &
bb_occ["x", "max"] > small_bound[1] &
bb_occ["y", "min"] < small_bound[4] &
bb_occ["y", "max"] > small_bound[4]) {
CC.confirmed <- append(CC.confirmed, i)
print("confirmed")
track <- 1
break
}
if (nrow(occ.df) < l) {
CC.not_confirmed <- append(CC.not_confirmed, i)
print("not confirmed")
track <- 1
break
}
}
if (track == 0) {
CC.not_confirmed <- append(CC.not_confirmed, i)
print("not confirmed")
}
}
return(
list(
no_data = CC.no_data,
not_confirmed = CC.not_confirmed,
confirmed = CC.confirmed
)
)
}
# Actual Steps
PP <- boundary_function(species, small_bound)
if (efficiency == TRUE) {
CC <- boundary_function(PP[["no_data"]], big_bound)
} else {
CC <- boundary_function(species, big_bound)
}
if (efficiency == TRUE) {
range_confirmed <- range_function(CC[["confirmed"]])
range_unconfirmed <- range_function(CC[["not_confirmed"]])
return(list(PP, CC, range_confirmed, range_unconfirmed))
} else {
range <- range_function(species)
return(list(PP, CC, range))
}
}
# Get the California Current System shape
CC_shape <- mr_features_get(
type = "MarineRegions:lme",
featureID = "lme.10",
format = "json"
)
# check that it's the right polygon
class(CC_shape) <- "mr_geojson"
CC_shape <- mr_as_wkt(CC_shape)
pnt <- st_as_sfc(CC_shape, crs = 4326)
mapview(pnt)
# Simplify the polygon for use with GBIF
CC_shape_sp <- st_transform(pnt, crs = "+proj=aeqd +lat_0=53.6 +lon_0=12.7")
mapview(CC_shape_sp)
CC_shape_sp <- st_simplify(CC_shape_sp,
preserveTopology = FALSE,
dTolerance = 20000
)
CC_shape_sp <- st_transform(CC_shape_sp, crs = 4326)
mapview(CC_shape_sp)
# Reverse order for GBIF
CC_shape_sp[[1]][[1]][, 1] <- rev(CC_shape_sp[[1]][[1]][, 1])
CC_shape_sp[[1]][[1]][, 2] <- rev(CC_shape_sp[[1]][[1]][, 2])
### GBIF Run###
# Run function that does GBIF analysis (this takes a long time; recommend running with job::job() when working in chunks)
distribution <- distribution_check(
c(-122.50, 37.49, -122.49, 37.50),
CC_shape_sp,
species_standardized,
5,
FALSE
)
### GBIF Summary###
# Organize the GBIF analysis output
d <- distribution
PP <- d[[1]]$confirmed
CC <- d[[2]]$confirmed
range <- d[[3]]$confirmed
no_data <- d[[3]]$no_data
df_PP <- c()
df_CC <- c()
df_range <- c()
df_no_data <- c()
df_not_in_GBIF <- c()
for (s in species_both$species) {
if (is.na(s)) {
df_not_in_GBIF <- append(df_not_in_GBIF, TRUE)
df_PP <- append(df_PP, NA)
df_CC <- append(df_CC, NA)
df_range <- append(df_range, NA)
df_no_data <- append(df_no_data, NA)
next
} else {
df_not_in_GBIF <- append(df_not_in_GBIF, FALSE)
}
if (s %in% PP) {
df_PP <- append(df_PP, TRUE)
} else {
df_PP <- append(df_PP, FALSE)
}
if (s %in% CC) {
df_CC <- append(df_CC, TRUE)
} else {
df_CC <- append(df_CC, FALSE)
}
if (s %in% range) {
df_range <- append(df_range, TRUE)
} else {
df_range <- append(df_range, FALSE)
}
if (s %in% no_data) {
df_no_data <- append(df_no_data, TRUE)
} else {
df_no_data <- append(df_no_data, FALSE)
}
}
GBIF_summary <- data.frame(
Species = species_both$verbatim_name,
GBIFSpecies = species_both$species,
PillarPointOccurrence = df_PP,
CCSOccurrence = df_CC,
Range = df_range,
NoData = df_no_data,
NotInGBIF = df_not_in_GBIF
)
percentages <- GBIF_summary %>%
group_by(across(PillarPointOccurrence:NotInGBIF)) %>%
summarise(count = n()) %>%
ungroup() %>%
mutate(per = count / sum(count))
known_summary <- as.numeric(GBIF_summary %>% filter(!is.na(GBIFSpecies)) %>% summarise(count = sum(Range == TRUE &
CCSOccurrence == TRUE)))
Focused on just the 159 (samples) samples, we removed
singletons and all 25 (overlap) ASVs that overlapped with
negative controls (Supplemental Information X), and we rarefied samples
to the minimum number of reads of any sample, leaving 27038
(processed_ASVs) ASVs and 4047981
(processed_reads) reads. 89.1%
(sprintf("%0.1f%%", unassigned_ASVs[unassigned_ASVs$Kingdom == "",]$freq * 100))
of ASVs were unassigned, and the remainder included representatives from
28 (unique["Phylum"]) phyla, 59
(unique["Class"]) classes, 132
(unique["Order"]) orders, 234
(unique["Family"]) families, 325
(unique["Genus"]) genera, and 415
(unique["Species"]) species (Figure 4). A breakdown of the
relative proportions of reads and ASVs assigned to each phyla can be
found in Table 1. To ensure the accuracy of these taxonomic
identifications, we confirmed that 298 (known_summary) of
415 (unique["Species"]) identified species (71.8%
sprintf("%0.1f%%", known_summary/unique["Species"] * 100))
have occurrence records in the California Current System (CCS) and known
ranges that encompass Pillar Point. (additional details in SI 1 and
Table S2).
### TABLE 1###
# Create table with summary of reads, ASVs, and species by phyla
# Remove all unclassified ASVs and condense to phylum level
physeq_totalreads <- tax_glom(physeq_summed, taxrank = "Phylum", NArm = TRUE)
Phyla_Reads <- data.frame(
Phyla = tax_table(physeq_totalreads)[, 2],
Reads = rowSums(otu_table(physeq_totalreads))
)
physeq_totalASVs <- physeq_summed
otu_table(physeq_totalASVs)[otu_table(physeq_totalASVs) > 0] <- 1
physeq_totalASVs <- tax_glom(physeq_totalASVs,
taxrank = "Phylum",
NArm = TRUE
)
Phyla_ASVs <- data.frame(
Phyla = tax_table(physeq_totalASVs)[, 2],
ASVs = rowSums(otu_table(physeq_totalASVs))
)
physeq_speciesbyphyla <- physeq_summed
physeq_speciesbytaxa <- tax_glom(physeq_summed,
taxrank = "Species",
NArm = TRUE
)
otu_table(physeq_speciesbytaxa)[otu_table(physeq_speciesbytaxa) > 0] <- 1
physeq_speciesbytaxa <- tax_glom(physeq_speciesbytaxa,
taxrank = "Phylum",
NArm = TRUE
)
Phyla_Species <- data.frame(
Phyla = tax_table(physeq_speciesbytaxa)[, 2],
Species = rowSums(otu_table(physeq_speciesbytaxa))
)
list <- list(Phyla_Reads, Phyla_ASVs, Phyla_Species)
full <- list %>% reduce(full_join, by = "Phylum")
full[is.na(full)] <- 0
full_sorted <- full[order(-full$Reads), ]
full_sorted <- full_sorted %>%
mutate(Reads_Percent = scales::label_percent()(Reads / sum(Reads))) %>%
mutate(ASVs_Percent = scales::label_percent()(ASVs / sum(ASVs))) %>%
mutate(Species_Percent = scales::label_percent()(Species / sum(Species)))
full_sorted$Phylum <- remove_NCBInums(full_sorted$Phylum)
full_sorted$Phylum <- str_replace(full_sorted$Phylum, "phylum_", "Class: ")
col_order <- c(
"Phylum",
"Reads",
"Reads_Percent",
"ASVs",
"ASVs_Percent",
"Species",
"Species_Percent"
)
full_sorted <- full_sorted[, col_order]
write.csv(full_sorted, "Analysis Products/Table1.csv", row.names = FALSE)
full_sorted
### Figure 4###
# Create phylogenetic tree for all taxonomic assignments
options(getClass.msg = FALSE)
# Aggregate to species assignment and remove the NCBI identifiers
pt_physeq <- tax_glom(data_physeq, taxrank = "Species", NArm = FALSE)
tax_table(pt_physeq) <- tax_table(pt_physeq)[!tax_table(pt_physeq)[, "Kingdom"] == ""]
tax_table(pt_physeq)[tax_table(pt_physeq) == ""] <- NA
tax_table(pt_physeq) <- tax_table(pt_physeq)[!is.na(tax_table(pt_physeq)[, "Phylum"])]
numbers <- sub(".*_", "", tax_table(pt_physeq))
taxa <- apply(numbers, 1, function(x) tail(na.omit(x), 1))
tax_table(pt_physeq) <- remove_NCBInums(tax_table(pt_physeq))
taxa_classification <- classification(taxa, db = "ncbi")
taxa_tree <- class2tree(taxa_classification, check = TRUE)
# Change the tip labels to match phyloseq objects (code only works if order is the same)
taxa_tree$phylo$tip.label <- row.names(tax_table(pt_physeq))
phyla <- unique(tax_table(pt_physeq)[, "Phylum"])
phyla_nodes <- c()
phyla_nodes <- data.frame("node_phylum" = c(), "node" = c())
phyla_nodes_secondary <- data.frame("node_phylum" = c(), "tips" = c())
for (x in phyla) {
OTUs <- na.omit(row.names(tax_table(pt_physeq))[tax_table(pt_physeq)[, "Phylum"] == x])
OTUs <- as.vector(OTUs)
num <- ape::getMRCA(taxa_tree$phylo, tip = OTUs)
if (is.null(num)) {
nodes <- as_tibble(taxa_tree$phylo)
num <- nodes$node[nodes$label == OTUs]
}
df <- data.frame("node_phylum" = c(x), "node" = c(num))
phyla_nodes <- rbind(phyla_nodes, df)
if (length(OTUs) < 6) {
for (y in OTUs) {
df2 <- data.frame("node_phylum" = c(x), "tips" = c(y))
phyla_nodes_secondary <- rbind(phyla_nodes_secondary, df2)
}
}
}
pt_physeq <- merge_phyloseq(pt_physeq, taxa_tree$phylo)
# Use Polychrome package to create a good color palette for the number of phyla
set.seed(567629)
colors <- createPalette(
28,
c("#FFFFFF"),
range = c(30, 80),
target = c("normal", "protanope", "deuteranope", "tritanope")
)
# Check whether the given order of colors has good contrast for different forms of colorblindness
pal.safe(colors)

# Manually re-order the colors to ensure there is good contrast between adjacent colors
colors_ordered <- colors[c(
"NC2",
"NC11",
"NC27",
"NC25",
"NC4",
"NC5",
"NC8",
"NC24",
"NC9",
"NC10",
"NC12",
"NC13",
"NC1",
"NC14",
"NC15",
"NC16",
"NC7",
"NC17",
"NC18",
"NC19",
"NC20",
"NC21",
"NC22",
"NC23",
"NC26",
"NC6",
"NC3",
"NC28"
)]
# Confirm that the new order works well
pal.safe(colors_ordered)

# Create ggtree
p <- ggtree::ggtree(pt_physeq, layout = "circular")
ordered_names <- ggtree::get_taxa_name(p)
ordered_names <- unique(ordered_names)
ordered_names[match(rownames(tax_table(pt_physeq)), ordered_names)] <- tax_table(pt_physeq)[, "Phylum"]
ordered_names <- unique(ordered_names)
names(colors_ordered) <- ordered_names
p <- p + geom_fruit(
geom = geom_tile,
mapping = aes(fill = Phylum),
width = 3,
show.legend = FALSE
) +
scale_fill_manual(values = colors_ordered) +
scale_color_manual(values = colors_ordered)
p <- p + geom_fruit(
data = phyla_nodes_secondary,
geom = geom_tile,
mapping = aes(y = tips, fill = node_phylum),
width = 6,
show.legend = FALSE
)
p <- p + ggtree::geom_hilight(
data = phyla_nodes,
mapping = aes(node = node, fill = node_phylum),
show.legend = FALSE
)
p <- p + ggtree::geom_cladelab(
data = phyla_nodes,
mapping = aes(node = node, label = node_phylum),
geom = "text",
angle = "auto",
offset = 5,
fontsize = 2,
barcolor = NA,
show.legend = FALSE
)
p <- p +
theme(
panel.background = element_rect(fill = "transparent"),
plot.background = element_rect(fill = "transparent", color = NA),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.background = element_rect(fill = "transparent"),
legend.box.background = element_rect(fill = "transparent")
)
path <- "Figures/Figure4."
save_pdf_png(
plot = p,
path = path,
w = 169,
h = 169,
u = "mm",
bg = "transparent",
dpi = 600
)
Figure 4: : Phylogenetic tree colored by the
phyla identified across all eDNA samples. Italicized taxonomic names are
those with no phylum-level assignment, so class-level assignments are
used to differentiate (additional information added after R figure
production)
3.2 Individual-Level Differences Between Locations
### Euler Diagrams###
eulerr_options(
quantities = list(fontsize = 10),
legend = list(fontsize = 14)
)
# Subset ampvis2 data by location
amp_S1 <- amp_filter_samples(data_amp, Location %in% c("S1"))
## 108 samples and 14365 OTUs have been filtered
## Before: 159 samples and 27038 OTUs
## After: 51 samples and 12673 OTUs
amp_S2 <- amp_filter_samples(data_amp, Location %in% c("S2"))
## 105 samples and 16586 OTUs have been filtered
## Before: 159 samples and 27038 OTUs
## After: 54 samples and 10452 OTUs
amp_N <- amp_filter_samples(data_amp, Location %in% c("N"))
## 105 samples and 15230 OTUs have been filtered
## Before: 159 samples and 27038 OTUs
## After: 54 samples and 11808 OTUs
# List the unique taxa at each location
S1_taxa <- unique(amp_S1$tax$Species)
S1_taxa <- S1_taxa[S1_taxa != ""]
S2_taxa <- unique(amp_S2$tax$Species)
S2_taxa <- S2_taxa[S2_taxa != ""]
N_taxa <- unique(amp_N$tax$Species)
N_taxa <- N_taxa[N_taxa != ""]
# List the unique ASVs at each locaton
S1_ASV <- unique(amp_S1$tax$OTU)
S2_ASV <- unique(amp_S2$tax$OTU)
N_ASV <- unique(amp_N$tax$OTU)
# Using eulerr, create euler diagrams for taxa and ASVs
add_quantity_line_break <- function(v) {
tags <-
v$children$canvas.grob$children$diagram.grob.1$children$tags$children
tags <- do.call(grid::gList, lapply(tags, function(x) {
x$children[[2]]$label <- sub(" \\%)", "%)", x$children[[2]]$label)
before <- gsub(" .*$", "", x$children[[2]]$label)
after <- gsub(".*\\(", "(", x$children[[2]]$label)
full <- bquote(atop(NA, atop(atop(
textstyle(.(before)), textstyle(italic(.(after)))
), NA)))
x$children[[2]]$label <- full
x$children[[2]]$just <- NULL
x
}))
v$children$canvas.grob$children$diagram.grob.1$children$tags <-
tags
return(v)
}
E_taxa <-
euler(list(S1 = S1_taxa, S2 = S2_taxa, N = N_taxa), shape = "ellipse")
E_taxa_plot <- plot(
E_taxa,
quantities = list(type = c("counts", "percent"), cex = 1),
legend = list(
side = "right",
nrow = 1,
ncol = 3,
cex = 1
)
)
E_taxa_plot <- add_quantity_line_break(E_taxa_plot)
unique_taxa_location <- (E_taxa$original.values["S1"] +
E_taxa$original.values["S2"] +
E_taxa$original.values["N"]) / sum(E_taxa$original.values)
E_ASV <-
euler(list(S1 = S1_ASV, S2 = S2_ASV, N = N_ASV), shape = "ellipse")
E_ASV_plot <- plot(
E_ASV,
quantities = list(type = c("counts", "percent"), cex = 1),
legend = list(
side = "right",
nrow = 1,
ncol = 3,
cex = 1
)
)
E_ASV_plot <- add_quantity_line_break(E_ASV_plot)
unique_ASV_location <- (E_ASV$original.values["S1"] +
E_ASV$original.values["S2"] +
E_ASV$original.values["N"]) / sum(E_ASV$original.values)
Across both taxa
(n=r unique["Species"]``unique["Species"]) and ASVs
(n=27038 processed_ASVs), all three locations had unique
elements, suggesting that there was not complete mixing of eDNA across
micro-habitats. 33.3%
sprintf("%0.1f%%", unique_taxa_location * 100) of taxa and
79.1% sprintf("%0.1f%%", unique_ASV_location * 100) of ASVs
were unique to one of the three locations (Figure 5). At both the taxa
and ASV level, S1 had more unique elements than S2 and nearshore,
although this effect was more pronounced across ASVs. ASVs and taxa
shared across pairs of two locations were the least common elements.
euler <- (wrap_elements(panel = grid::textGrob(
"A)",
hjust = 6,
vjust = 1,
gp = gpar(fontsize = 14, fontface = "bold")
)) +
wrap_elements(panel = grid::textGrob(
"B)",
hjust = 6,
vjust = 1,
gp = gpar(fontsize = 14, fontface = "bold")
))) /
(
wrap_elements(panel = E_taxa_plot$children$canvas.grob) + wrap_elements(panel = E_ASV_plot$children$canvas.grob)
) /
wrap_elements(panel = E_taxa_plot$children$legend.grob) + plot_layout(heights = c(1, 10, 1))
path <- "Figures/Figure5."
save_pdf_png(
plot = euler,
path = path,
w = 169,
h = 110,
u = "mm",
bg = "transparent",
dpi = 600
)
Figure 5: Area-proportional Euler diagrams
showing the overlap in taxa (A) and ASVs (B) between locations S1, S2,
and N.
### Indicator Species Analysis###
# Function for creating indicator species heatmap from physeq data
indicator_heatmap <- function(physeq, asv) {
# If analyzing by taxa, remove all unclassified ASVs and condense to species assignments
if (asv == FALSE) {
physeq <- tax_glom(physeq, taxrank = "Species", NArm = TRUE)
tax_table(physeq) <- remove_NCBInums(tax_table(physeq))
} else {
tax_table(physeq) <- remove_NCBInums(tax_table(physeq))
}
# Convert to presence/absence data
otu_table(physeq)[otu_table(physeq) > 0] <- 1
# Use indicspecies package to get top taxa
indval <- multipatt(
t(otu_table(physeq)),
t(sample_data(physeq)[, "Location"]),
control = how(nperm = 999),
duleg = TRUE
)
top_N <- rownames(indval$sign %>%
filter(p.value < 0.05) %>%
filter(s.N == 1) %>%
filter(stat > .7))
top_S1 <- rownames(indval$sign %>%
filter(p.value < 0.05) %>%
filter(s.S1 == 1) %>%
filter(stat > .7))
top_S2 <- rownames(indval$sign %>%
filter(p.value < 0.05) %>%
filter(s.S2 == 1) %>%
filter(stat > .7))
indicators_all <- c(top_N, top_S1, top_S2)
# Merge samples by site/time before plotting
physeq_merge <- merge_samples(physeq, "SiteByTime")
# Update metadata accordingly
updated_metadata <- as.matrix(sample_data(physeq)[, c(
"SiteByTime",
"Time",
"Location",
"T",
"S"
)])
updated_metadata <- as.data.frame(updated_metadata)
updated_metadata$SiteByTime <- as.factor(updated_metadata$SiteByTime)
updated_metadata$Time <- as.factor(updated_metadata$Time)
updated_metadata$Location <- as.factor(updated_metadata$Location)
updated_metadata <- distinct(updated_metadata)
rownames(updated_metadata) <- updated_metadata[, "SiteByTime"]
sample_data(physeq_merge) <- sample_data(updated_metadata)
# Divide all merged samples by the number of samples they represent
otu_table(physeq_merge) <- otu_table(physeq_merge) / 3
otu_table(physeq_merge)[grepl("11:30", rownames(otu_table(physeq_merge)))] <- otu_table(physeq_merge)[grepl("11:30", rownames(otu_table(physeq_merge)))] /
3
otu_table(physeq_merge)[grepl("14:00", rownames(otu_table(physeq_merge)))] <- otu_table(physeq_merge)[grepl("14:00", rownames(otu_table(physeq_merge)))] /
3
otu_table(physeq_merge)[grepl("17:00", rownames(otu_table(physeq_merge)))] <- otu_table(physeq_merge)[grepl("17:00", rownames(otu_table(physeq_merge)))] /
3
# Add labels to the indicator species for plotting
indicators_only <-
prune_taxa(colnames(otu_table(physeq_merge)) %in% indicators_all, physeq_merge)
add_indicator_label <- function(X) {
if (X %in% top_N) {
return("N")
} else if (X %in% top_S1) {
return("S1")
} else if (X %in% top_S2) {
return("S2")
} else {
return("NA")
}
}
indicators <-
sapply(rownames(tax_table(indicators_only)), add_indicator_label)
tax_table(indicators_only) <- cbind(tax_table(indicators_only), indicators)
# Plot
plot <- plot_heatmap(
indicators_only,
method = NULL,
distance = NULL,
trans = NULL,
taxa.order = rev(indicators_all),
taxa.label = "Species",
sample.label = "Time",
sample.order = "Time"
) +
facet_grid(
factor(indicators, levels = c("S1", "S2", "N")) ~ factor(Location,
levels =
c("S1", "S2", "N")
),
scales = "free",
space = "free",
switch = "y"
) +
scale_fill_gradient(low = "black", high = "#B5D7E4") +
theme_grey(base_size = 10) +
theme(plot.title = element_text(hjust = 0.5)) +
theme(axis.text.x = element_text(
angle = 45,
vjust = 1,
hjust = 1
)) +
theme(strip.placement = "outside") +
theme(strip.text = element_text(size = rel(1))) +
theme(legend.position = "bottom") +
theme(
panel.background = element_blank(),
panel.grid.major = element_blank()
) +
labs(fill = "Proportion of Positive Detects", title = "Locations") +
theme(
axis.ticks = element_line(color = "black"),
axis.text.y = element_text(color = "black", face = "italic"),
axis.text.x = element_text(color = "black")
) +
guides(fill = guide_colorbar(barwidth = 10))
plot$scales$scales[[2]]$name <- "Indicators"
return(
list(
plot = plot,
top_N = top_N,
top_S1 = top_S1,
top_S2 = top_S2,
all_indicators = indicators_all,
full_output = indval
)
)
}
heatmap_taxa <- indicator_heatmap(data_physeq, FALSE)
heatmap_ASV <- indicator_heatmap(data_physeq, TRUE)
indicator_ASVs <- data_amp$tax[heatmap_ASV$all_indicators, ]
unassigned_indicator_ASVs <- indicator_ASVs %>%
group_by(Kingdom) %>%
summarise(n = n()) %>%
mutate(freq = n / sum(n))
identify_new_indicators <- function(data_amp, top_ASVs, top_taxa) {
top_ASVs <- data_amp$tax[top_ASVs, ]
top_taxa <- data_amp$tax[top_taxa, ]
top_ASVs <- top_ASVs$Species[top_ASVs$Species != ""]
top_taxa <- top_taxa$Species
top_ASVs <- remove_NCBInums(top_ASVs)
top_taxa <- remove_NCBInums(top_taxa)
return(setdiff(top_ASVs, top_taxa))
}
N_ASV_extra <- sort(identify_new_indicators(data_amp, heatmap_ASV$top_N, heatmap_taxa$top_N))
S1_ASV_extra <- sort(identify_new_indicators(data_amp, heatmap_ASV$top_S1, heatmap_taxa$top_S1))
S2_ASV_extra <- sort(identify_new_indicators(data_amp, heatmap_ASV$top_S2, heatmap_taxa$top_S2))
path <- "Figures/Figure6."
save_pdf_png(
plot = heatmap_taxa$plot,
path = path,
w = 169,
h = 100,
u = "mm",
bg = "transparent",
dpi = 600
)
Figure 6: Heat map of identified indicator
taxa for all three locations over time, scaled by the number of
replicates that detected that species.
Using an indicator species framework produced similar trends to the
analysis of unique taxa and ASVs; all three locations had indicator taxa
and ASVs, and S1 had more indicator elements than other locations. By
taxa, we identified 11 length(heatmap_taxa$all_indicators)
indicator taxa: 7 length(heatmap_taxa$top_S1) for S1, 3
length(heatmap_taxa$top_S2) for S2, and 1
length(heatmap_taxa$top_N) for nearshore (Figure 6). By
ASVs, we found more indicators overall. We identified 99
length(heatmap_ASV$all_indicators) indicator ASVs: 72
length(heatmap_ASV$top_S1) for S1, 10
length(heatmap_ASV$top_S2) for S2, and 17
length(heatmap_ASV$top_N) for nearshore (Supplemental
Figure X). Most (78.8%
sprintf("%0.1f%%", unassigned_indicator_ASVs[unassigned_indicator_ASVs$Kingdom == "",]$freq * 100))
indicator ASVs had no taxonomic assignment, but the ones that did
included several species beyond the original indicator taxa, at S1
(Bossiella frondescens, Bossiella plumosa, Corallina confusa,
Leathesia difformis, Myrionema balticum, Scorpaenichthys marmoratus
toString(S1_ASV_extra)), S2 (Bossiella frondescens,
Smithora naiadum toString(S2_ASV_extra)), and
nearshore (Halichondria panicea, Mazzaella splendens, Smithora
naiadum, Strongylocentrotus purpuratus
toString(N_ASV_extra)).
3.4. Ecological Significance
### Ecological Significance Preparation###
# Create data frame with unique and indicator species from each site
S1_unique <- setdiff(S1_taxa, union(S2_taxa, N_taxa))
S2_unique <- setdiff(S2_taxa, union(S1_taxa, N_taxa))
N_unique <- setdiff(N_taxa, union(S2_taxa, S1_taxa))
S1 <- data.frame(list(Species = remove_NCBInums(S1_unique), Unique = "S1"))
S2 <- data.frame(list(Species = remove_NCBInums(S2_unique), Unique = "S2"))
N <- data.frame(list(Species = remove_NCBInums(N_unique), Unique = "N"))
unique <- rbind(S1, S2, N)
S1_i <- data.frame(list(
Species = remove_NCBInums(data_amp$tax$Species[rownames(data_amp$tax) %in% heatmap_taxa$top_S1]),
Indicator = "S1"
))
S2_i <- data.frame(list(
Species = remove_NCBInums(data_amp$tax$Species[rownames(data_amp$tax) %in% heatmap_taxa$top_S2]),
Indicator = "S2"
))
N_i <- data.frame(list(
Species = remove_NCBInums(data_amp$tax$Species[rownames(data_amp$tax) %in% heatmap_taxa$top_N]),
Indicator = "N"
))
indicators <- rbind(S1_i, S2_i, N_i)
df_list <- list(unique, indicators)
full_taxa_list <- df_list %>% reduce(full_join, by = "Species")
# Identify taxonomic synonyms for all species in above data frame
synonyms <- c()
for (s in full_taxa_list$Species) {
worms_ID <- get_wormsid(s)
if (is.na(worms_ID)) {
syns <- NA
} else {
syns <- synonyms(worms_ID, db = "worms")
syns <- toString(syns[[1]]$scientificname)
}
synonyms <- rbind(synonyms, syns)
}
full_taxa_list <- cbind(full_taxa_list, synonyms)
# Clean species text in data frame
# Remove anything in parentheticals
full_taxa_list$synonyms <-
gsub("\\s*\\([^\\)]+\\)", "", full_taxa_list$synonyms)
# Remove anything beyond two words in each comma separated section
for (syn in 1:length(full_taxa_list$synonyms)) {
all <- unlist(strsplit(full_taxa_list$synonyms[syn], ","))
if (!is.na(all[1])) {
for (i in 1:length(all)) {
all[i] <- str_trim(all[i])
all[i] <- sub("^(\\S*\\s+\\S+).*", "\\1", all[i])
}
}
syns <- toString(unique(all))
full_taxa_list$synonyms[syn] <- syns
}
write.csv(full_taxa_list,
"Analysis Products/BPT_Analysis.csv",
row.names = FALSE
)
### Ecological Significance PDF Reading###
# Read in needed text of Between Pacific Tides (files not given on GitHub due to copyright)
# PDFs obtained from 5th Edition of Between Pacific Tides available digitally through DeGruyter
# Link to Access: https://doi-org.stanford.idm.oclc.org/10.1515/9781503621329
# BetweenPacificTides_TextForSeaching.pdf is a compilation of the following PDF sections from DeGruyter, aligned so the PDF page numbers match the text page numbers
# Introduction, 1 Outer-Coast Rocky Shores, 2 Outer-Coast Sandy Beaches, 3 Open-Coast Rocky Shores, 4 Open-Coast Sandy Beaches, 5 Rocky Shores of Bays and Estuaries, 6 Sand Flats, 7 Eelgrass Flats, 8 Mud Flats, 9 Exposed Piles, 10 Protected Piles
# BetweenPacificTides_TOC.pdf is the Contents PDF section from DeGruyter
# Check to only run these steps if you have the proper PDFs in your Data folder
if (file.exists("Data/BetweenPacificTides_TextForSearching.pdf") &
file.exists("Data/BetweenPacificTides_TOC.pdf")) {
txt <- pdf_text("Data/BetweenPacificTides_TextForSearching.pdf")
toc <- pdf_text("Data/BetweenPacificTides_TOC.pdf")
# Clean up PDF text
# First remove places where there's a hyphen added over a line break "-\n"
# Then remove all line breaks "\n"
txt <- gsub("-\n", "", txt)
txt <- gsub("\n", " ", txt)
# Clean up TOC
toc <- strsplit(toc, "\n")
toc <- c(toc[[1]], toc[[2]], toc[[3]])
page_nums <- grepl("[1234567890,]$", toc)
toc <- toc[page_nums]
# Fix the couple of strings that are split over multiple lines
toc_cleaned <- c(toc[1:14], paste0(toc[15], toc[16]), toc[17:21], paste0(toc[22], toc[23]), toc[24:53])
toc_cleaned <- as.data.frame(toc_cleaned)
toc_cleaned <- extract(toc_cleaned,
toc_cleaned,
into = c("text", "page"),
"(.*)\\s+([^ ]+)$"
)
toc_cleaned$page <- as.numeric(toc_cleaned$page)
toc_cleaned_max <- vector()
for (x in 1:(nrow(toc_cleaned) - 1)) {
if (toc_cleaned$page[x] == toc_cleaned$page[x + 1]) {
toc_cleaned_max[x] <- toc_cleaned$page[x]
} else {
toc_cleaned_max[x] <- toc_cleaned$page[x + 1] - 1
}
}
toc_cleaned_max[nrow(toc_cleaned)] <- NA
toc_cleaned$max_page <- toc_cleaned_max
# Remove everything not referring to rocky shores
toc_cleaned <- toc_cleaned[1:17, ]
# Remove just rows with zone
toc_zones <- toc_cleaned %>% filter(grepl("Zone", text))
toc_zones$text <- gsub("\\..*", "", toc_zones$text)
toc_zones$text <- trimws(toc_zones$text)
}
### Ecological Significance Text Searching###
# Check to only run these steps if you've been able to properly run the above text importing
if (exists("toc_zones") & exists("txt")) {
output <- c()
for (x in 1:length(full_taxa_list$Species)) {
species <- full_taxa_list$Species[x]
synonyms <- full_taxa_list$synonyms[x]
synonyms <- unlist(strsplit(synonyms, ", "))
all <- c(species, synonyms)
all_abbreviated <- sub("[a-z]* ", ". ", all)
all_to_search <- c(all, all_abbreviated)
all_pages <- vector()
for (y in all_to_search) {
pages <- grep(y, txt, ignore.case = FALSE, fixed = TRUE)
all_pages <- c(all_pages, pages)
}
all_pages <- unique(all_pages)
output[x] <- list(all_pages)
}
full_taxa_list$pages <- output
full_taxa_list$pages[sapply(full_taxa_list$pages, function(x) {
length(x) == 0
})] <- NA
zones <- unique(toc_zones$text)
df <- data.frame(matrix(ncol = length(zones), nrow = 0))
colnames(df) <- zones
name <- c()
zone <- c()
page <- c()
for (x in 1:length(full_taxa_list$pages)) {
list <- full_taxa_list$pages[[x]]
if (!is.na(list[1])) {
for (y in 1:length(list)) {
num <- list[y]
for (z in 1:length(toc_zones$text)) {
min <- toc_zones$page[z]
max <- toc_zones$max[z]
if (num <= max && num >= min) {
name <- append(name, full_taxa_list$Species[x])
zone <- append(zone, toc_zones$text[z])
page <- append(page, num)
} else {
}
}
}
}
}
final_1 <- as.data.frame(cbind(name, zone, page))
write.csv(final_1,
"Analysis Products/BPT_Analysis_Intermediate.csv",
row.names = FALSE
)
}
### Ecological Signifiance Cleaning + Statistical Analysis###
final_1 <- read.csv("Analysis Products/BPT_Analysis_Intermediate.csv")
# Split "Zones 1 and 2" into two entries
to_split <- final_1 %>%
filter(zone == "Zones 1 and 2") %>%
mutate(zone = "Zone 1")
final_2 <- final_1 %>% mutate(zone = replace(zone, zone == "Zones 1 and 2", "Zone 2"))
final_2 <- rbind(final_2, to_split)
# Split "Zones 2 and 3" into two entries
to_split <- final_1 %>%
filter(zone == "Zones 2 and 3") %>%
mutate(zone = "Zone 2")
final_2 <- final_2 %>% mutate(zone = replace(zone, zone == "Zones 2 and 3", "Zone 3"))
final_2 <- rbind(final_2, to_split)
condense <- final_2 %>% pivot_wider(
names_from = zone,
values_from = page,
values_fn = unique(list())
)
condense <- left_join(condense, full_taxa_list[, c("Species", "Unique", "Indicator")], by = join_by(name == Species))
condense <- condense %>% mutate(Site = coalesce(Unique, Indicator))
condense <- condense %>% relocate(Site, Unique, Indicator, name, "Zone 4", "Zone 3", "Zone 2", "Zone 1")
condense <- condense %>% rename(
Zone_1 = "Zone 1",
Zone_2 = "Zone 2",
Zone_3 = "Zone 3",
Zone_4 = "Zone 4"
)
condense_no_pages <- condense
condense_no_pages$Zone_1 <- !sapply(condense_no_pages$Zone_1, is.null)
condense_no_pages$Zone_2 <- !sapply(condense_no_pages$Zone_2, is.null)
condense_no_pages$Zone_3 <- !sapply(condense_no_pages$Zone_3, is.null)
condense_no_pages$Zone_4 <- !sapply(condense_no_pages$Zone_4, is.null)
# Adjust Based on Manual Checking in BPT
# Remove "Proboscidactyla flavicirrata" because search identified the wrong abbreviated synonym
condense_no_pages <- condense_no_pages %>% filter(name != "Proboscidactyla flavicirrata")
# Add "Laminaria setchellii" because it was found manually and only appears in a diagram (so not in text search)
condense_no_pages <- condense_no_pages %>% add_row(
Site = "N",
Unique = "N",
Indicator = NA,
name = "Laminaria setchellii",
Zone_4 = TRUE,
Zone_3 = FALSE,
Zone_2 = FALSE,
Zone_1 = FALSE
)
# Add "Egregia menziesii" because it was found manually through the index, but only appears by genus in the text
condense_no_pages <- condense_no_pages %>% add_row(
Site = "S2",
Unique = "S2",
Indicator = NA,
name = "Egregia menziesii",
Zone_4 = TRUE,
Zone_3 = TRUE,
Zone_2 = TRUE,
Zone_1 = FALSE
)
# Add "Pandalus danae" because it was found manually through the index, but only appears by genus in the text
condense_no_pages <- condense_no_pages %>% add_row(
Site = "S2",
Unique = "S2",
Indicator = NA,
name = "Pandalus danae",
Zone_4 = TRUE,
Zone_3 = FALSE,
Zone_2 = FALSE,
Zone_1 = FALSE
)
# Adjust "Ectopleura marina" to include Zone_3 (found manually because mentioned on that page with genus only, but linked in the index)
condense_no_pages <- condense_no_pages %>%
mutate(Zone_3 = replace(Zone_3, name == "Ectopleura marina", TRUE))
# Adjust "Halosydna brevisetosa" to include Zone_4 (found manually because mentioned on that page with genus only, but linked in the index)
condense_no_pages <- condense_no_pages %>%
mutate(Zone_4 = replace(Zone_4, name == "Halosydna brevisetosa", TRUE))
# Sort the species list
condense_no_pages <- condense_no_pages %>%
arrange(name) %>%
arrange(desc(Zone_1), desc(Zone_2), desc(Zone_3), desc(Zone_4)) %>%
arrange(factor(Site, levels = c("S1", "S2", "N")))
# Organize species list for chi square test
contingency_table <- condense_no_pages %>%
group_by(Site) %>%
summarise(
High = sum(Zone_1 == TRUE |
Zone_2 == TRUE |
Zone_3 == TRUE),
Low = sum(Zone_1 == FALSE & Zone_2 == FALSE & Zone_3 == FALSE)
)
contingency_table <- contingency_table %>%
dplyr::select(-Site) %>%
as.matrix()
rownames(contingency_table) <- c("N", "S1", "S2")
set.seed(1)
test <- chisq.test(contingency_table,
correct = FALSE,
simulate.p.value = TRUE
)
test_post_hoc <- chisq.posthoc.test(contingency_table,
method = "bonferroni",
simulate.p.value = TRUE
)
### Figure 9###
# Create table to display results
for_plotting <- condense_no_pages
for_plotting <- for_plotting %>% mutate(
Unique = replace(Unique, !is.na(Unique), "X"),
Unique = replace(Unique, is.na(Unique), ""),
Indicator = replace(Indicator, !is.na(Indicator), "X"),
Indicator = replace(Indicator, is.na(Indicator), "")
)
for_plotting <- for_plotting %>%
gt(groupname_col = "Site", id = "mygt") %>%
tab_spanner(
label = "Intertidal Zones",
columns = c(Zone_4, Zone_3, Zone_2, Zone_1)
) %>%
tab_options(row_group.as_column = TRUE) %>%
gt_color_rows("Zone_4", palette = c("white", "#D1E7C7")) %>%
gt_color_rows("Zone_3", palette = c("white", "#BBBED1")) %>%
gt_color_rows("Zone_2", palette = c("white", "#BBBED1")) %>%
gt_color_rows("Zone_1", palette = c("white", "#BBBED1")) %>%
tab_style(
style = cell_text(style = "italic"),
locations = cells_body(columns = name)
) %>%
tab_style(
style = cell_text(color = "#FFFFFF00", size = "x-small"),
locations = cells_body(columns = c("Zone_4", "Zone_3", "Zone_2", "Zone_1"))
) %>%
tab_style(
style = cell_text(size = px(12)),
locations = cells_body(columns = c("Unique", "Indicator", "name"))
) %>%
cols_align(
align = "center",
columns = c("Unique", "Indicator")
) %>%
cols_label(
Zone_1 = "1",
Zone_2 = "2",
Zone_3 = "3",
Zone_4 = "4",
name = "Species",
Unique = "Uniq.\nTo",
Indicator = "Indic.\nOf"
) %>%
tab_style(
style = cell_text(v_align = "middle"),
locations = cells_row_groups()
) %>%
tab_style(
style = cell_borders(
sides = c("bottom"),
color = "black",
weight = px(3)
),
locations = list(cells_column_spanners(), cells_column_labels())
) %>%
tab_style(
style = cell_borders(
sides = "all",
color = "black",
weight = px(3)
),
locations = list(cells_row_groups())
) %>%
tab_style(
style = cell_borders(
sides = "all",
color = "black"
),
locations = cells_body()
) %>%
tab_style(
style = cell_borders(
sides = "bottom",
color = "black",
weight = px(3)
),
locations = cells_body(rows = c(18, 31, 41))
) %>%
tab_style(
style = cell_borders(
sides = "right",
color = "black",
weight = px(3)
),
locations = cells_body(columns = 8)
) %>%
tab_options(data_row.padding = px(1)) %>%
data_color(
columns = Unique,
rows = Unique == "X",
palette = "lightgray",
) %>%
data_color(
columns = Indicator,
rows = Indicator == "X",
palette = "lightgray",
) %>%
tab_options(table.border.top.style = "hidden") %>%
tab_style(
style = cell_text(align = "center"),
locations = cells_column_labels(columns = name)
)
path <- "Figures/Figure9.png"
gtsave(for_plotting, filename = path)
Identified unique and indicator taxa reflected known ecological
differences between locations. Only a subset of unique and indicator
taxa were described in Between Pacific Tides: 20.8%
sprintf("%0.1f%%", length(which(condense_no_pages$Site=="N"))/length(which(full_taxa_list$Unique=="N" | full_taxa_list$Indicator=="N")) * 100)
(10 length(which(condense_no_pages$Site=="N"))/48
length(which(full_taxa_list$Unique=="N" | full_taxa_list$Indicator=="N")))
of nearshore taxa, 34.0%
sprintf("%0.1f%%", length(which(condense_no_pages$Site=="S1"))/length(which(full_taxa_list$Unique=="S1" | full_taxa_list$Indicator=="S1")) * 100)
(18 length(which(condense_no_pages$Site=="S1"))/53
length(which(full_taxa_list$Unique=="S1" | full_taxa_list$Indicator=="S1")))
of S1 taxa, and 28.9%
sprintf("%0.1f%%", length(which(condense_no_pages$Site=="S2"))/length(which(full_taxa_list$Unique=="S2" | full_taxa_list$Indicator=="S2")) * 100)
(13 length(which(condense_no_pages$Site=="S2"))/45
length(which(full_taxa_list$Unique=="S2" | full_taxa_list$Indicator=="S2")))
of S2. However, across the subset present in Between Pacific Tides, more
taxa from S1 were categorized to the highest intertidal zones (Zone 1 -
uppermost horizon, Zone 2 - high, and Zone 3 - middle) than S2 and N
(Figure 9). The proportion of taxa from highest intertidal zones varied
significantly across locations (χ2 =8.4195324
test$statistic, p = 0.017991 test$p.value),
matching the environmental characteristics of the sites.
Figure 9: Chart habitat information about
unique and indicator species present in Between Pacific Tides
LS0tCnRpdGxlOiAiRW52aXJvbm1lbnRhbCBETkEgbWV0YWJhcmNvZGluZyBkaWZmZXJlbnRpYXRlcyBiZXR3ZWVuIG1pY3JvLWhhYml0YXRzIHdpdGhpbiB0aGUgcm9ja3kgaW50ZXJ0aWRhbCIKYXV0aG9yOiAiTWVnaGFuIE0uIFNoZWEiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICBkZl9wcmludDogcGFnZWQKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwotLS0KCmBgYHtyLCBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB0aWR5ID0gInN0eWxlciIpCmBgYAoKYGBge3IsIExvYWRpbmcgUGFja2FnZXMsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCByZXN1bHRzID0gRkFMU0V9CiMjI0xvYWRpbmcgUGFja2FnZXMjIyMKCnJlbnY6OnJlc3RvcmUoKQoKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoc2YpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoZXVsZXJyKQpsaWJyYXJ5KGluZGljc3BlY2llcykKbGlicmFyeShjbHVzdGVyKQpsaWJyYXJ5KHZlZ2FuKQpsaWJyYXJ5KGNoaXNxLnBvc3Rob2MudGVzdCkKbGlicmFyeSh0YXhpemUpCmxpYnJhcnkoUG9seWNocm9tZSkKbGlicmFyeShwYWxzKQpsaWJyYXJ5KHNwb2NjKQpsaWJyYXJ5KG1yZWdpb25zKQpsaWJyYXJ5KHJnYmlmKQpsaWJyYXJ5KG1hcHZpZXcpCmxpYnJhcnkoZ2diZWVzd2FybSkKbGlicmFyeShnZ2g0eCkKbGlicmFyeShjaHVua2hvb2tzKQpsaWJyYXJ5KGRldnRvb2xzKQpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoc3R5bGVyKQpsaWJyYXJ5KHBoeWxvc2VxKQpsaWJyYXJ5KGdndHJlZSkKbGlicmFyeShnZ3RyZWVFeHRyYSkKbGlicmFyeShhbXB2aXMyKQpsaWJyYXJ5KHBkZnRvb2xzKQpsaWJyYXJ5KGd0KQpsaWJyYXJ5KGd0RXh0cmFzKQoKaG9va19maWd1cmVfdW5pdCgpCmBgYAoKYGBge3IsIENvcmUgRnVuY3Rpb25zfQojIyNDb3JlIEZ1bmN0aW9ucyMjIwojQ29sbGVjdGlvbiBvZiBmdW5jdGlvbnMgdXNlZCBhY3Jvc3MgYW5hbHlzZXMKCiNGdW5jdGlvbiB0aGF0IHJlbW92ZXMgTkNCSSBUYXhvbm9teSBJRHMgZnJvbSB0aGUgZW5kIG9mIHRheG9ub21pYyBuYW1lcyAoYXMgaW4gdGhlIEFuYWNhcGEgUGlwZWxpbmUgb3V0cHV0KSAKcmVtb3ZlX05DQkludW1zID0gZnVuY3Rpb24obGlzdCkgewogIGxpc3QgPSBzdWIoIl9bXl9dKyQiLCAiIiwgbGlzdCkKICByZXR1cm4obGlzdCkKfQoKI0Z1bmN0aW9uIHRoYXQgY29udmVydHMgYW4gYW1wdmlzMiBvYmplY3QgdG8gYSBwaHlsb3NlcSBvYmplY3QKI0NhbiBiZSB1c2VkIGVpdGhlciBvbiBhbiBleGlzdGluZyBhbXB2aXMyIG9iamVjdCAoYWJ1bmQsIHRheCwgbWQgPSBOVUxMKSBvciBzZXBhcmF0ZSBhYnVuZCwgdGF4LCBhbmQgbWV0YWRhdGEgZGF0YSBmcmFtZXMgKGFtcHZpcyA9IE5VTEwpCmFtcF90b19waHlsb3NlcSA9IGZ1bmN0aW9uKGFtcHZpcywgYWJ1bmQsIHRheCwgbWQpIHsKICBpZiAoIWlzLm51bGwoYW1wdmlzKSkgewogICAgcGh5c2VxID0gcGh5bG9zZXEoCiAgICAgIG90dV90YWJsZShhcy5tYXRyaXgoYW1wdmlzJGFidW5kKSwgdGF4YV9hcmVfcm93cyA9IFRSVUUpLAogICAgICB0YXhfdGFibGUoYXMubWF0cml4KGFtcHZpcyR0YXgpKSwKICAgICAgc2FtcGxlX2RhdGEoYW1wdmlzJG1ldGFkYXRhKQogICAgKQogIH0gZWxzZSBpZiAoaXMubnVsbChtZCkpIHsKICAgIHBoeXNlcSA9IHBoeWxvc2VxKG90dV90YWJsZShhcy5tYXRyaXgoYWJ1bmQpLCB0YXhhX2FyZV9yb3dzID0gVFJVRSksCiAgICAgICAgICAgICAgICAgICAgICB0YXhfdGFibGUoYXMubWF0cml4KHRheCkpKQogIH0gZWxzZSB7CiAgICBwaHlzZXEgPSBwaHlsb3NlcSgKICAgICAgb3R1X3RhYmxlKGFzLm1hdHJpeChhYnVuZCksIHRheGFfYXJlX3Jvd3MgPSBUUlVFKSwKICAgICAgdGF4X3RhYmxlKGFzLm1hdHJpeCh0YXgpKSwKICAgICAgc2FtcGxlX2RhdGEobWQpCiAgICApCiAgfQogIHJldHVybihwaHlzZXEpCn0KCiNGdW5jdGlvbiB0aGF0IHNhdmVzIC5wbmcgYW5kIC5wZGYgdmVyc2lvbnMgb2YgYSBnaXZlbiBmaWd1cmUKc2F2ZV9wZGZfcG5nID0gZnVuY3Rpb24ocGxvdCwgcGF0aCwgdywgaCwgdSwgYmcsIGRwaSkgewogIGZvciAoeCBpbiBjKCJwZGYiLCAicG5nIikpIHsKICAgIGdnc2F2ZSgKICAgICAgcGxvdCA9IHBsb3QsCiAgICAgIGZpbGVuYW1lID0gcGFzdGUwKHBhdGgsIHgpLAogICAgICBkZXZpY2UgPSB4LAogICAgICBiZyA9IGJnLAogICAgICB3aWR0aCA9IHcsCiAgICAgIGhlaWdodCA9IGgsCiAgICAgIHVuaXRzID0gdSwKICAgICAgZHBpID0gZHBpCiAgICApCiAgfQp9CmBgYAoKIyMjIE1hdGVyaWFscyBhbmQgTWV0aG9kcwoKIyMjIyAyLjEgRGV0YWlsZWQgUHJvdG9jb2xzCgpUbyBpbXByb3ZlIHJlcHJvZHVjaWJpbGl0eSAoZS5nLiBEaWNraWUgZXQgYWwuLCAyMDE4OyBTaGVhIGV0IGFsLiwgMjAyMyksIGVuYWJsZSBvcGVuIGRhdGEgc2NpZW5jZSAoZS5nLiBGcmVkc3RvbiBhbmQgTG93bmRlcywgMjAyNCksIGFuZCBhaWQgaW4gdGhlIGluaXRpYXRpb24gb2YgbmV3IGVETkEgYmlvbW9uaXRvcmluZyBwcm9qZWN0cywgd2UgaGF2ZSBwdWJsaXNoZWQgZGV0YWlsZWQsIHN0ZXAtYnktc3RlcCBwcm90b2NvbHMgZm9yIG1hbnkgb2YgdGhlIG1ldGhvZHMgZGVzY3JpYmVkLCBpbmNsdWRpbmcgc3BlY2lmaWMgbWF0ZXJpYWxzIHVzZWQsIHBob3RvZ3JhcGhzLCBhbmQgYWRkaXRpb25hbCBtZXRob2RvbG9naWNhbCBub3RlcyBub3QgcG9zc2libGUgdG8gaW5jbHVkZSBoZXJlLiBTZWUgU2hlYSBhbmQgQm9laG0gZm9yIHNhbXBsZSBjb2xsZWN0aW9uIGFuZCBmaWx0ZXJpbmcgKFsyMDIzYl0oaHR0cHM6Ly9keC5kb2kub3JnLzEwLjE3NTA0L3Byb3RvY29scy5pby5icDJsNjl5N2tscWUvdjIpKSwgZm9yIEROQSBleHRyYWN0aW9ucyAoWzIwMjNjXShodHRwczovL2R4LmRvaS5vcmcvMTAuMTc1MDQvcHJvdG9jb2xzLmlvLmV3b3YxcXl5eWdyMi92MSkpLCBmb3IgUENSIGFtcGxpZmljYXRpb24gKFsyMDIzZF0oaHR0cHM6Ly9keC5kb2kub3JnLzEwLjE3NTA0L3Byb3RvY29scy5pby5kbTZncDN3cGR2enAvdjEpKSwgYW5kIGZvciBzaGlwcGluZyBzYW1wbGVzIChbMjAyM2VdKGh0dHBzOi8vZHguZG9pLm9yZy8xMC4xNzUwNC9wcm90b2NvbHMuaW8uZG02Z3AzOGpwdnpwL3YxKSkuIEFkZGl0aW9uYWxseSwgd2UgaGF2ZSBwdWJsaXNoZWQgYWxsIGRhdGEgYW5kIGNvZGUgZm9yIHJlcGxpY2F0aW5nIG91ciBhbmFseXNlcyB2aWEgRHJ5YWQgKFtTaGVhICYgQm9laG0sIDIwMjRdKGh0dHBzOi8vZG9pLm9yZy8xMC41MDYxL2RyeWFkLnBudngwazZ0ZikpLCBpbmNsdWRpbmcgRkFTVFEgZmlsZXMgYW5kIGVETkEgZGF0YXNldHMgKHByZS1wcm9jZXNzaW5nICYgcG9zdC1wcm9jZXNzaW5nKS4gVGhyb3VnaCBEcnlhZCBhbmQgWmVub2RvLCBvdXIgbW9kaWZpZWQgQW5hY2FwYSBDb250YWluZXIgYW5kIHNjcmlwdHMgZm9yIGJpb2luZm9ybWF0aWNzIChbU2hlYSAmIEJvZWhtLCAyMDIzYV0oaHR0cHM6Ly96ZW5vZG8ub3JnL2RvaS8xMC41MjgxL3plbm9kby44MjAxMTQwKSksIGFzIHdlbGwgYXMgYSBHaXRIVWIgcmVwb3NpdG9yeSBpbmNsdWRpbmcgYW4gUiBNYXJrZG93biBmaWxlIHRoYXQgcmVwcm9kdWNlcyBhbGwgbWV0aG9kcyAmIHJlc3VsdHMgZGV0YWlsZWQgaGVyZSAoW1NoZWEgJiBCb2VobSwgMjAyM2ZdKGh0dHBzOi8vemVub2RvLm9yZy9kb2kvMTAuNTI4MS96ZW5vZG8uODIxMzA1MCkpIGNhbiBhbHNvIGJlIGFjY2Vzc2VkLgoKIyMjIyAyLjIgU2FtcGxpbmcgU2l0ZQoKVG8gYmV0dGVyIHVuZGVyc3RhbmQgc3BhdGlhbCBhbmQgdGVtcG9yYWwgZGlmZmVyZW5jZXMgaW4gZUROQSBzaWduYWxzIGluIGEgY29tcGxleCBjb2FzdGFsIGVudmlyb25tZW50LCB3ZSBzb3VnaHQgYSByb2NreSBpbnRlcnRpZGFsIGZpZWxkIGxvY2F0aW9uIHRoYXQgaGFkIGNvbnNpc3RlbnQsIGxhcmdlLCBhY2Nlc3NpYmxlIHRpZGUgcG9vbHMgdGhhdCB3ZXJlIGZ1bGx5IGlzb2xhdGVkIGZyb20gb25lIGFub3RoZXIgYXQgc29tZSBsb3cgdGlkZXMgYnV0IGludGVyY29ubmVjdGVkIGR1cmluZyBvdGhlciBwYXJ0cyBvZiB0aGVpciBleHBvc3VyZSBwZXJpb2QuIFdlIHNlbGVjdGVkIHRoZSBpbnRlcnRpZGFsIGF0IFBpbGxhciBQb2ludCwgYSBoZWFkbGFuZHMgcHJvbW9udG9yeSB0byB0aGUgd2VzdCBvZiBQaWxsYXIgUG9pbnQgSGFyYm9yIGluIFNhbiBNYXRlbyBDb3VudHksIENhbGlmb3JuaWEsIFVTQS4gUGlsbGFyIFBvaW50IGlzIGEgcG9wdWxhciByZWNyZWF0aW9uYWwgaW50ZXJ0aWRhbCBhcmVhIHRoYXQgaXMgZGlyZWN0bHkgYWRqYWNlbnQgdG8gdGhlIFBpbGxhciBQb2ludCBTdGF0ZSBNYXJpbmUgQ29uc2VydmF0aW9uIEFyZWEgKG5vIHNwZWNpZmljIHVzZSBzY2llbnRpZmljIGNvbGxlY3Rpb24gcGVybWl0IHJlcXVpcmVkKS4KCldpdGhpbiBQaWxsYXIgUG9pbnQsIHdlIHNhbXBsZWQgYXQgdGhyZWUgZGlzY3JldGUgbG9jYXRpb25zOiB0d28gaW5kaXZpZHVhbCB0aWRlIHBvb2xzIHdpdGggYSByYW5nZSBvZiBwaHlzaWNhbCBjb25uZWN0aXZpdHkgKFRpZGUgUG9vbCAxLCBTMTogMzcuNDk1MzA2wrAsIC0xMjIuNDk4NzQ0wrA7IFRpZGUgUG9vbCAyLCBTMjogMzcuNDk0OTkywrAsIC0xMjIuNDk4OTU1wrApIGFuZCBhbiBlcXVpZGlzdGFudCBsb2NhdGlvbiAoTmVhcnNob3JlLCBOOiAzNy40OTUyODjCsCwgLTEyMi40OTkxOTjCsCkgd2hlcmUgdGhlcmUgd2FzIHdlbGwtbWl4ZWQgb2Zmc2hvcmUgd2F0ZXIgZm9yIHRoZSBkdXJhdGlvbiBvZiB0aGUgdGlkYWwgY3ljbGUgKEZpZ3VyZSAyOyBub3QgcHJvZHVjZWQgaW4gUikuIEVhY2ggc2l0ZSB3YXMgYXBwcm94aW1hdGVseSA0MCBtZXRlcnMgZnJvbSBhbGwgb3RoZXIgc2l0ZXMuIFRpZGUgUG9vbCAxIGFuZCBUaWRlIFBvb2wgMiBhcmUgZnVsbHkgaXNvbGF0ZWQgYXQgdGlkYWwgaGVpZ2h0cyBvZiBhcm91bmQgMCBtIChtZWFuIGxvdyBsb3cgd2F0ZXIsIE1MTFcpIG9yIGxvd2VyLCBhbmQgc3Vic3RhbnRpYWxseSBjb25uZWN0ZWQgYXQgYXJvdW5kIDAuMjUgbSBvciBoaWdoZXIuIE9uIHRoZSBkYXkgd2Ugc2FtcGxlZCwgdGhpcyBtZWFudCB3YXRlciBhY3RpdmVseSBmbG93ZWQgYmV0d2VlbiB0aGUgbG9jYXRpb25zIGF0IHRoZSBzdGFydCAoMTE6MzAgUFNUKSBhbmQgZW5kICgxNzowMCBQU1QpIG9mIHRoZSBzYW1wbGluZyBwZXJpb2QsIGJ1dCB0aGF0IHRoZSBzaXRlcyB3ZXJlIGRpc2Nvbm5lY3RlZCBhdCBsb3cgdGlkZSBpbiB0aGUgbWlkZGxlIG9mIHRoZSBzYW1wbGluZyBwZXJpb2QuIEVjb2xvZ2ljYWxseSwgVGlkZSBQb29sIDEgd2FzIGxvY2F0ZWQgY2xvc2VyIHRvIHNob3JlIGFuZCBpbnRlcmlvciB0byBhIGNoYW5uZWwgdGhhdCBkaXZpZGVzIHRoZSBQaWxsYXIgUG9pbnQgaW50ZXJ0aWRhbCwgY2hhcmFjdGVyaXN0aWMgb2YgdGhlIGhpZ2ggdG8gbWlkZGxlIGludGVydGlkYWwuIFRpZGUgUG9vbCAyIHdhcyBsb2NhdGVkIGFjcm9zcyB0aGUgY2hhbm5lbCBhbmQgZnVydGhlciBmcm9tIHNob3JlLCBjaGFyYWN0ZXJpc3RpYyBvZiB0aGUgbG93IGludGVydGlkYWwuIAoKIyMjIyAyLjMgU2FtcGxlIENvbGxlY3Rpb24gJiBGaWx0cmF0aW9uCgpXZSBjb2xsZWN0ZWQgMSBMIHN1cmZhY2Ugc2FtcGxlcyBmcm9tIGVhY2ggc2l0ZSBldmVyeSAzMCBtaW51dGVzIGZvciB0aGUgZHVyYXRpb24gb2YgdGltZSB0aGUgcm9ja3kgaW50ZXJ0aWRhbCB3YXMgZXhwb3NlZCBvbiAyOCBKYW51YXJ5IDIwMjIsIHVzaW5nIHNpbmdsZS11c2UgZW50ZXJhbCBmZWVkaW5nIHBvdWNoZXMgKENvdmlkaWVuLCBEdWJsaW4sIElyZWxhbmQpLiBUaGUgc2FtcGxpbmcgdm9sdW1lIHVzZWQsIDEgTCwgaGFzIGJlZW4gc2hvd24gdG8gYmUgc3VmZmljaWVudCBmb3IgZGV0ZWN0aW5nIGEgcmVwcmVzZW50YXRpdmUgcmFuZ2Ugb2YgbWFyaW5lIG9yZ2FuaXNtcyBpbiBuZWFyc2hvcmUgbG9jYXRpb25zIChHb2xkIGV0IGFsLiwgMjAyMikgYW5kIGlzIGNvbW1vbmx5IHVzZWQgaW4gYXF1YXRpYyBlRE5BIHN0dWRpZXMgKFRha2FoYXNoaSBldCBhbC4sIDIwMjMpLiBTYW1wbGluZyBjb21tZW5jZWQgYXQgMTE6MzAgUFNUOyB0aGUgZXhhY3QgdGltZXMgb2Ygc2FtcGxlIGNvbGxlY3Rpb24sIGluIHJlbGF0aW9uIHRvIHRoZSB0aWRlLCBhcmUgc2hvd24gaW4gRmlndXJlIDMuIEF0IGVhY2ggc2l0ZSwgc2FtcGxlcyB3ZXJlIGNvbGxlY3RlZCBmcm9tIGEgY29uc2lzdGVudCBwb3NpdGlvbiBhY3Jvc3MgdGltZSBwb2ludHMuIEZvbGxvd2luZyB0aGUgYXBwcm9hY2ggdXNlZCBieSBHb2xkIGV0IGFsLiAoMjAyMWIpLCB3ZSBhdHRhY2hlZCBhIHN0ZXJpbGUgMC4yMiAkXG11JG0gcG9yZSBzaXplIFN0ZXJpdmV4IGNhcnRyaWRnZSAoTWlsbGlwb3JlU2lnbWEsIEJ1cmxpbmd0b24sIE1BLCBVU0EpIHRvIHRoZSB0dWJpbmcgb2YgZWFjaCBmZWVkaW5nIHBvdWNoLCBhbGxvd2luZyBzYW1wbGVzIHRvIGJlIGltbWVkaWF0ZWx5IGdyYXZpdHkgZmlsdGVyZWQgaW4gdGhlIGZpZWxkLiBXaGlsZSBncmF2aXR5IGZpbHRlcmluZyAoMS0yIGhvdXJzIHBlciBzYW1wbGUpLCBzYW1wbGVzIHdlcmUgc2hhZGVkIHdpdGggYW4gYXduaW5nIHRvIHByZXZlbnQgYW55IGRlZ3JhZGF0aW9uIGJ5IHN1bmxpZ2h0IChBbmRydXN6a2lld2ljeiBldCBhbC4sIDIwMTcpLk9uZSBzYW1wbGUgZmVsbCBkdXJpbmcgZ3Jhdml0eSBmaWx0cmF0aW9uLCByZXN1bHRpbmcgaW4gYSBtaXNzaW5nIHNhbXBsZSBmcm9tIFMxIGF0IDE2OjAwIFBTVC4gCgpgYGB7ciwgRmlndXJlIDN9CiMjI0ZpZ3VyZSAzIyMjCiNQcm9kdWNlIHRoZSB0b3AgcG9ydGlvbiBvZiBGaWd1cmUgMyBmcm9tIHRpZGUgZGF0YQoKI1JlYWQgUGlsbGFyIFBvaW50IE5PQUEvTk9TL0NPLU9QcyBUaWRlIENoYXJ0IGRhdGEgZmlsZQpUaWRlcyA9IHJlYWQudGFibGUoCiAgIkRhdGEvMjgtSmFuLTIwMjItVGlkZUNoYXJ0LnR4dCIsCiAgaGVhZGVyID0gVFJVRSwKICBzZXAgPSAiIiwKICBkZWMgPSAiLiIsCiAgc2tpcCA9IDEzCikKCiNDb252ZXJ0IGRhdGUgZm9ybWF0IGluIHRhYmxlIHVzaW5nIGx1YnJpZGF0ZQpUaWRlcyRkYXRldGltZSA8LQogIGx1YnJpZGF0ZTo6eW1kX2htKHBhc3RlKFRpZGVzJERhdGUsIFRpZGVzJFRpbWUpLCB0eiA9ICJVUy9QYWNpZmljIikKCiNTZXQgYm91bmRzIG9mIHNhbXBsaW5nIHBlcmlvZCB0byBoaWdobGlnaHQKeG1pbiA9IFRpZGVzJGRhdGV0aW1lWzQ3XQp4bWF4ID0gVGlkZXMkZGF0ZXRpbWVbNjldCnltaW4gPSAtLjUKeW1heCA9IC41Cgpib3hfY29sb3IgPSAiI0MwQzBDMCIKCiNDcmVhdGUgcGxvdCBvZiBmdWxsIHRpZGFsIGN5Y2xlIHdpdGggc2FtcGxpbmcgcGVyaW9kIGhpZ2hsaWdodGVkCnAxIDwtIGdncGxvdChkYXRhID0gVGlkZXMsIGFlcyh4ID0gZGF0ZXRpbWUsIHkgPSBQcmVkLCBncm91cCA9IDEpKSArCiAgYW5ub3RhdGUoCiAgICAicmVjdCIsCiAgICB4bWluID0geG1pbiwKICAgIHhtYXggPSB4bWF4LAogICAgeW1pbiA9IHltaW4sCiAgICB5bWF4ID0geW1heCwKICAgIGZpbGwgPSBib3hfY29sb3IKICApICsKICBnZW9tX2xpbmUoKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKFRpZGVzJGRhdGV0aW1lWzFdLCBUaWRlcyRkYXRldGltZVs5Nl0pKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxMikgKwogIHRoZW1lKAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkFfY2hhcmFjdGVyXyksCiAgICAjIG5lY2Vzc2FyeSB0byBhdm9pZCBkcmF3aW5nIHBhbmVsIG91dGxpbmUKICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkFfY2hhcmFjdGVyXyksCiAgICAjIG5lY2Vzc2FyeSB0byBhdm9pZCBkcmF3aW5nIHBsb3Qgb3V0bGluZQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiYmxhY2siKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIiksCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoCiAgICAgIGNvbG91ciA9ICJibGFjayIsCiAgICAgIGZpbGwgPSBOQSwKICAgICAgbGluZXdpZHRoID0gMQogICAgKQogICkgKwogIHhsYWIoIlRpbWUgKFBTVCkiKSArCiAgeWxhYigiTUxMVyBUaWRlIFByZWRpY3Rpb24gKG0pIikgKwogIHNjYWxlX3hfZGF0ZXRpbWUoCiAgICBkYXRlX2JyZWFrcyA9ICIyIGhvdXIiLAogICAgZGF0ZV9sYWJlbHMgPSAiJUg6MDAiLAogICAgZXhwYW5kID0gYygwLCAwKSwKICAgIHBvc2l0aW9uID0gInRvcCIKICApCgojQ3JlYXRlIHBsb3Qgb2YganVzdCBzYW1wbGluZyBwZXJpb2QKcDIgPC0gZ2dwbG90KGRhdGEgPSBUaWRlcywgYWVzKHggPSBkYXRldGltZSwgeSA9IFByZWQsIGdyb3VwID0gMSkpICsKICBnZW9tX2xpbmUoKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKHhtaW4sIHhtYXgpLCB5bGltID0gYyh5bWluLCB5bWF4KSkgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTIpICsKICB0aGVtZSgKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IGJveF9jb2xvciksCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BX2NoYXJhY3Rlcl8pLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiYmxhY2siKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIiksCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoCiAgICAgIGNvbG91ciA9ICJibGFjayIsCiAgICAgIGZpbGwgPSBOQSwKICAgICAgbGluZXdpZHRoID0gMQogICAgKQogICkgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHlsYWIoIk1MTFcgVGlkZSBQcmVkaWN0aW9uIChtKSIpICsKICBzY2FsZV94X2RhdGV0aW1lKGRhdGVfYnJlYWtzID0gIjMwIG1pbiIsCiAgICAgICAgICAgICAgICAgICBkYXRlX2xhYmVscyA9ICIlSDolTSIsCiAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBjKDAsIDApKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oYiA9IDApKQoKI1N0aXRjaCBwbG90cyB0b2dldGhlciB1c2luZyBwYXRjaHdvcmsKcF9wYXRjaCA8LQogIHAxIC8gKHAyICYKICAgICAgICAgIHRoZW1lKHBsb3QubWFyZ2luID0gZ2dwbG90Mjo6bWFyZ2luKDAsIDAsIDAsIDAsICJwdCIpKSkgJgogIHlsYWIoTlVMTCkgJgogIHRoZW1lKHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3VyID0gTkFfY2hhcmFjdGVyXykpCgojIFVzZSB0aGUgdGFnIGxhYmVsIGFzIGEgeS1heGlzIGxhYmVsCnBfcGF0Y2ggPSB3cmFwX2VsZW1lbnRzKHBfcGF0Y2gpICsKICBsYWJzKHRhZyA9ICJNTExXIFRpZGUgUHJlZGljdGlvbiAobSkiKSArCiAgdGhlbWUoCiAgICBwbG90LnRhZyA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuMiksIGFuZ2xlID0gOTApLAogICAgcGxvdC50YWcucG9zaXRpb24gPSAibGVmdCIsCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9IE5BX2NoYXJhY3Rlcl8pCiAgKQoKaWYgKCFkaXIuZXhpc3RzKCJGaWd1cmVzIikpIHsKICBkaXIuY3JlYXRlKCJGaWd1cmVzIikKfQpwYXRoID0gIkZpZ3VyZXMvRmlndXJlMy4iCnNhdmVfcGRmX3BuZygKICBwbG90ID0gcF9wYXRjaCwKICBwYXRoID0gcGF0aCwKICB3ID0gMTY5LAogIGggPSA5MCwKICB1ID0gIm1tIiwKICBiZyA9ICJ0cmFuc3BhcmVudCIsCiAgZHBpID0gNjAwCikKYGBgCgo8Y2VudGVyPgoKIVsqRmlyc3QgY29tcG9uZW50IG9mIEZpZ3VyZSAzIChzZWNvbmQgc2VjdGlvbiBhZGRlZCBvbmNlIGRhdGEgaGFzIGJlZW4gbG9hZGVkKl0oYHIgcGFzdGUwKHBhdGgsICJwbmciKWApCgo8L2NlbnRlcj4KCkF0IHRocmVlIHRpbWUgcG9pbnRzIChzZWUgZnVsbCBGaWd1cmUgMywgZmluYWxpemVkIGJlbG93KSBhdCB0aGUgYmVnaW5uaW5nIGFuZCBlbmQgb2YgdGhlIHNhbXBsaW5nIHBlcmlvZCBhcyB3ZWxsIGFzIGF0IGxvdyB0aWRlIChhdCAxNDowMCBQU1QpLCB3ZSBjb2xsZWN0ZWQgdHJpcGxpY2F0ZSAxIEwgc2FtcGxlcyBmcm9tIGVhY2ggbG9jYXRpb24gYXMgYmlvbG9naWNhbCByZXBsaWNhdGVzLiBBdCB0aGUgYmVnaW5uaW5nIGFuZCBlbmQgb2YgdGhlIHNhbXBsaW5nIHBlcmlvZCwgd2UgYWxzbyBmaWx0ZXJlZCAxIEwgTWlsbGlRIHdhdGVyIHZpYSB0aGUgcHJvY2VkdXJlIGRlc2NyaWJlZCBhYm92ZSB0byBzZXJ2ZSBhcyBuZWdhdGl2ZSBmaWVsZCBjb250cm9scy4gQWRkaXRpb25hbGx5LCB1c2luZyBhbiBPcmlvbiBNb2RlbCAxMjMwIG1ldGVyIChPcmlvbiBSZXNlYXJjaCBJbmMuLCBCZXZlcmx5LCBNQSwgVVNBKSwgd2UgcmVjb3JkZWQgdGVtcGVyYXR1cmUgYW5kIHNhbGluaXR5IGluIGVhY2ggbG9jYXRpb24gZGlyZWN0bHkgYWZ0ZXIgc2FtcGxlcyB3ZXJlIGNvbGxlY3RlZC4KCk9uY2UgZmluaXNoZWQgZmlsdGVyaW5nLCBTdGVyaXZleCBjYXJ0cmlkZ2VzIHdlcmUgZHJpZWQgYnkgcHVzaGluZyBhaXIgdGhyb3VnaCB0aGVtIHVzaW5nIGEgc3RlcmlsZSAzIG1MIHN5cmluZ2UsIGNhcHBlZCwgcGxhY2VkIGluIHN0ZXJpbGUgV2hpcmwtUGFrIGJhZ3MgKFdoaXJsLVBhaywgTWFkaXNvbiwgV0ksIFVTQSkuIFRoZW4sIHNhbXBsZXMgd2VyZSBzdG9yZWQgaW4gYSBjb29sZXIgb24gaWNlIHVudGlsIHRyYW5zcG9ydGVkIGJhY2sgdG8gdGhlIGxhYm9yYXRvcnkgYXQgdGhlIGVuZCBvZiB0aGUgc2FtcGxpbmcgcGVyaW9kLiBTYW1wbGVzIHdlcmUgdHJhbnNmZXJyZWQgdG8gYSAtMjDCsEMgZnJlZXplciBmb3IgdXAgdG8gMTggZGF5cywgYXQgd2hpY2ggdGltZSB0aGV5IHdlcmUgcHJvY2Vzc2VkIHRvIGV4dHJhY3QgbnVjbGVpYyBhY2lkcyBmcm9tIHRoZSBjYXB0dXJlZCBtYXRlcmlhbHMuIFRoaXMgc2FtcGxpbmcgc2NoZW1lIHJlc3VsdGVkIGluIDUzIGZpZWxkIHNhbXBsZXMuIAoKIyMjIyAyLjQgRE5BIEV4dHJhY3Rpb24gJiBMaWJyYXJ5IFByZXBhcmF0aW9uCgpXaXRoaW4gMTggZGF5cyBvZiBjb2xsZWN0aW9uLCB3ZSBleHRyYWN0ZWQgRE5BIGZyb20gdGhlIFN0ZXJpdmV4IGNhcnRyaWRnZSB1c2luZyB0aGUgRE5lYXN5IEJsb29kIGFuZCBUaXNzdWUgS2l0IChRaWFnZW4sIEdlcm1hbnRvd24sIE1ELCBVU0EpIGFuZCB0aGUgbW9kaWZpY2F0aW9ucyBkZXNjcmliZWQgaW4gU3BlbnMgZXQgYWwuICgyMDE3KS4gSW4gc2hvcnQsIHdlIGluY3ViYXRlZCB0aGUgZmlsdGVyIGNhcnRyaWRnZSBvdmVybmlnaHQgd2l0aCBwcm90ZWluYXNlIEsgYW5kIEFUTC4gVGhlbiwgd2UgZXh0cmFjdGVkIHRoZSBsaXF1aWQgZnJvbSB0aGUgY2FydHJpZGdlIHdpdGggYSBzeXJpbmdlIGFuZCBtaXhlZCBpdCB3aXRoIGVxdWFsIHZvbHVtZXMgb2YgQUwgYnVmZmVyIGFuZCAwwrBDIGV0aGFub2wgYmVmb3JlIHByb2NlZWRpbmcgd2l0aCB0aGUgbWFudWZhY3R1cmVyJ3MgZXh0cmFjdGlvbiBwcm90b2NvbC4gT25lIG5lZ2F0aXZlIGV4dHJhY3Rpb24gY29udHJvbCAoRE5BLWdyYWRlIHdhdGVyIGluIHBsYWNlIG9mIGEgc2FtcGxlKSB3YXMgaW5jbHVkZWQgaW4gZWFjaCBvZiBmb3VyIGJhdGNoZXMgb2YgZXh0cmFjdGlvbnMuIEV4dHJhY3RlZCBzYW1wbGVzIHRvIGJlIFBDUiBhbXBsaWZpZWQgd2VyZSBzdG9yZWQgYXQgLTIwwrBDIGZvciB1cCB0byA2IG1vbnRocy4gRE5BIGV4dHJhY3Rpb25zIHdlcmUgY29uZHVjdGVkIGF0IGEgbGFiIGJlbmNoIGRpc3RhbnQgZnJvbSBhbGwgc3Vic2VxdWVudCBoYW5kbGluZyBvZiBQQ1IgcHJvZHVjdHMuICAKCldlIFBDUiBhbXBsaWZpZWQgdGhlIGV4dHJhY3RlZCBETkEgaW4gdHJpcGxpY2F0ZSB3aXRoaW4gNiBtb250aHMgb2Ygc3RvcmFnZSwgdXNpbmcgdGhlIG1sQ09JaW50Ri8gamdIQ08yMTk4IHByaW1lciBzZXQgdGFyZ2V0aW5nIGEgMzEzIGJwIGZyYWdtZW50IG9mIHRoZSBtaXRvY2hvbmRyaWFsIENPSSByZWdpb24gb3B0aW1pemVkIGJ5IExlcmF5IGV0IGFsLiAoMjAxMykgKEZvcndhcmQ6IEdHV0FDV0dHV1RHQUFDV0dUV1RBWUNDWUNDOyBSZXZlcnNlOiBUQUlBQ1lUQ0lHR1JUR0lDQ1JBQVJBQVlDQSkgd2l0aCBOZXh0ZXJhIG1vZGlmaWNhdGlvbnMuIEZvbGxvd2luZyBDdXJkIGV0IGFsLiAoMjAxOSksIHdlIHVzZWQgYSAyNSAkXG11JGwgUENSIHJlYWN0aW9uIG1peHR1cmUgY29uc2lzdGluZyBvZiAxMi41ICRcbXUkbCBvZiBRaWFnZW4gTXVsdGlwbGV4IE1peCAoUWlhZ2VuLCBHZXJtYW50b3duLCBNRCwgVVNBKSwgMi41ICRcbXUkbCBlYWNoIG9mIHRoZSBmb3J3YXJkIGFuZCByZXZlcnNlIHByaW1lcnMgYXQgMiAkXG11JE0gKEludGVncmF0ZWQgRE5BIFRlY2hub2xvZ2llcywgSW5jLiwgQ29yYWx2aWxsZSwgSUEsIFVTQSksIDYuNSAkXG11JGwgb2YgUENSLWdyYWRlIHdhdGVyLCBhbmQgMSAkXG11JGwgb2YgdW5kaWx1dGVkIEROQSB0ZW1wbGF0ZS4gVGhlIFBDUiB0aGVybW9jeWNsaW5nIHRvdWNoZG93biBwcm9maWxlIGJlZ2FuIHdpdGggYW4gaW5pdGlhbCBkZW5hdHVyYXRpb24gYXQgOTXCsCBmb3IgMTUgbWludXRlcyB0byBhY3RpdmF0ZSB0aGUgRE5BIHBvbHltZXJhc2UsIGZvbGxvd2VkIGJ5IDEzIGN5Y2xlcyBvZiBkZW5hdHVyYXRpb24gKDk0wrAgZm9yIDMwIHNlY29uZHMpLCBhbm5lYWxpbmcgKHN0YXJ0aW5nIGF0IDY5LjXCsCBmb3IgMzAgc2Vjb25kcywgd2l0aCB0aGUgdGVtcGVyYXR1cmUgZGVjcmVhc2VkIGJ5IDEuNcKwIGVhY2ggY3ljbGUpLCBhbmQgZXh0ZW5zaW9uICg3MsKwIGZvciAxIG1pbnV0ZSkuIFRoZW4sIGFuIGFkZGl0aW9uYWwgMzUgY3ljbGVzIHdlcmUgcnVuIHdpdGggdGhlIHNhbWUgZGVuYXR1cmF0aW9uIGFuZCBleHRlbnNpb24gc3RlcHMgYXMgYWJvdmUgd2l0aCBhbiBhbm5lYWxpbmcgdGVtcGVyYXR1cmUgb2YgNTDCsCwgZm9sbG93ZWQgYnkgYSBmaW5hbCBleHRlbnNpb24gYXQgNzLCsCBmb3IgMTAgbWludXRlcy4gUENSIHJlYWN0aW9ucyB3ZXJlIHByZXBhcmVkIGluIGEgZGVzaWduYXRlZCBETkEtZnJlZSBob29kIHVudGlsIHRoZSB0ZW1wbGF0ZSB3YXMgYWRkZWQuCgpQQ1IgYW1wbGlmaWNhdGlvbiB3YXMgY29uZHVjdGVkIGluIHR3byBiYXRjaGVzOyBpbiBlYWNoIGJhdGNoLCB3ZSBpbmNsdWRlZCBvbmUgbm8tdGVtcGxhdGUgbmVnYXRpdmUgUENSIGNvbnRyb2wgKEROQS1ncmFkZSB3YXRlciB1c2VkIGFzIHRlbXBsYXRlKS4gQWRkaXRpb25hbGx5LCB3ZSBleHRyYWN0ZWQgRE5BIGZyb20gdGlzc3VlIGZyb20gZml2ZSBvcmdhbmlzbXMgYWNyb3NzIGEgcmFuZ2Ugb2YgcGh5bGEgd2UgZXhwZWN0ZWQgdG8gYW1wbGlmeSB3aXRoIHRoZSBtbENPSWludEYvIGpnSENPMjE5OCBwcmltZXJzLCBidXQgbm90IGV4cGVjdGVkIHRvIGJlIHByZXNlbnQgYXQgUGlsbGFyIFBvaW50IGluIHBhcnRpY3VsYXIgKCpNeXRpbHVzIGVkdWxpcyosICpNaXp1aG9wZWN0ZW4geWVzc29lbnNpcyosICpYaXBoaWFzIGdsYWRpdXMqLCAqTWVyY2VuYXJpYSBtZXJjZW5hcmlhKiwgKkx1dGphbnVzIGNhbXBlY2hhbnVzKikgdXNpbmcgdGhlIHN0YW5kYXJkIHRpc3N1ZSBleHRyYWN0aW9uIHByb3RvY29sIGRldGFpbGVkIGluIHRoZSBETmVhc3kgQmxvb2QgYW5kIFRpc3N1ZSBLaXQgKFFpYWdlbiwgR2VybWFudG93biwgTUQsIFVTQSkuIFRoZXNlIHRpc3N1ZXMgd2VyZSBvYnRhaW5lZCBmcm9tIGEgbG9jYWwgZ3JvY2VyeSBzdG9yZSBhbmQgaXQgd2FzIGFzc3VtZWQgdGhhdCB0aGV5IHdlcmUgbGFiZWxlZCBjb3JyZWN0bHksIGFsdGhvdWdoIHByZXZpb3VzIHdvcmsgaGFzIGluZGljYXRlZCBtaXNsYWJlbGluZyBpbiBzZWFmb29kIHN0b3JlcyBjYW4gb2NjdXIgKGUuZy4gV2lsbGV0dGUgZXQgYWwuLCAyMDE3KS4gRXh0cmFjdHMgZnJvbSB0aGUgNSB0aXNzdWUgc2FtcGxlcyB3ZXJlIGNvbWJpbmVkIGluIGVxdWltb2xhciBhbW91bnRzIHRvIGZvcm0gYSBtb2NrIGNvbW11bml0eSB1c2VkIGFzIGEgcG9zaXRpdmUgUENSIGNvbnRyb2wgaW4gZWFjaCBiYXRjaC4gVHJpcGxpY2F0ZSBQQ1IgYW1wbGljb25zIGZyb20gYm90aCBzYW1wbGVzIGFuZCBjb250cm9scyB3ZXJlIG5vdCBzdWJzZXF1ZW50bHkgcG9vbGVkLCBidXQgd2VyZSBjYXJyaWVkIHRocm91Z2ggdGhlIHJlbWFpbmluZyBsaWJyYXJ5IHByZXBhcmF0aW9uIGFuZCBzZXF1ZW5jaW5nIHN0ZXBzIGFzIHRlY2huaWNhbCByZXBsaWNhdGVzLiBXZSBlbGVjdHJvcGhvcmVzZWQgYW5kIHZpc3VhbGl6ZWQgYSBzdWJzZXQgb2YgUENSIHByb2R1Y3RzIG9uIGEgMS41JSBhZ2Fyb3NlIGdlbCBzdGFpbmVkIHdpdGggR2VsUmVkwq4gKEJpb3RpdW0sIEZyZW1vbnQsIENBLCBVU0EpIHRvIGVuc3VyZSBzdWNjZXNzZnVsIGFtcGxpZmljYXRpb24gYW5kIGNvcnJlY3QgcHJvZHVjdCBzaXplcyBhcyB3ZWxsIGFzIGxhY2sgb2YgY29udGFtaW5hdGlvbi4KClBvc3QtUENSIGxpYnJhcnkgcHJlcGFyYXRpb24gYW5kIHNlcXVlbmNpbmcgd2FzIGNvbmR1Y3RlZCBhdCB0aGUgR2VvcmdpYSBHZW5vbWljcyBhbmQgQmlvaW5mb3JtYXRpY3MgQ29yZSAoR0dCQywgVUcgQXRoZW5zLCBHQSwgUlJJRDpTQ1JfMDEwOTk0KS4gSW4gc2hvcnQsIHByb3ZpZGVkIFBDUiBhbXBsaWNvbnMgd2VyZSBjbGVhbmVkIHVzaW5nIEFNUHVyZSBYUCBtYWduZXRpYyBiZWFkcyAoQmVja21hbiBDb3VsdGVyLCBJbmRpYW5hcG9saXMsIElOLCBVU0EpLCBiYXJjb2RlZCB3aXRoIE5leHRlcmEgYWRhcHRlcnMgKElsbHVtaW5hLCBTYW4gRGllZ28sIENBLCBVU0EpIGR1cmluZyBhIHNlY29uZCBQQ1IgKDMgbWluIGF0IDk1wrBDOyAxNSBjeWNsZXMgb2YgMzAgc2VjIGF0IDk1wrBDLCAzMCBzZWMgYXQgNjfCsEMsIGFuZCAzMCBzZWMgYXQgNzLCsEM7IGFuZCA0IG1pbiBhdCA3MsKwQyksIGNsZWFuZWQgYWdhaW4gdXNpbmcgQU1QdXJlWFAgbWFnbmV0aWMgYmVhZHMsIGFuZCBwb29sZWQgaW4gZXF1aW1vbGFyIHJhdGlvLiBUaGUgcmVzdWx0aW5nIGxpYnJhcnkgd2FzIHNlcXVlbmNlZCBvbiBhIE1pU2VxIFBFIDJ4MjUwYnAgKDUwMCBjeWNsZXMpIHVzaW5nIFJlYWdlbnQgS2l0IFYyIHdpdGggMjUlIFBoaVggc3Bpa2UtaW4gKElsbHVtaW5hLCBTYW4gRGllZ28sIENBLCBVU0EpLiBHaXZlbiBvdXIgdGVjaG5pY2FsIHJlcGxpY2F0aW9uIG9mIHNhbXBsZXMgYW5kIGNvbnRyb2xzLCBvdXIgZmluYWwgbGlicmFyeSBpbmNsdWRlZCA2IG5lZ2F0aXZlIGZpZWxkIGNvbnRyb2xzICgxIGF0IGJlZ2lubmluZyBhbmQgZW5kIG9mIGZpZWxkIHNhbXBsaW5nLCBhbXBsaWZpZWQgaW4gdHJpcGxpY2F0ZSksIDEyIG5lZ2F0aXZlIGV4dHJhY3Rpb24gY29udHJvbHMgKDEgaW4gZWFjaCBvZiA0IGV4dHJhY3Rpb24gc2V0cywgYW1wbGlmaWVkIGluIHRyaXBsaWNhdGUpLCAyIHBvc2l0aXZlIFBDUiBjb250cm9scyAoMSBpbiBlYWNoIG9mIDIgYW1wbGlmaWNhdGlvbiBiYXRjaGVzKSwgMiBuby10ZW1wbGF0ZSBuZWdhdGl2ZSBQQ1IgY29udHJvbHMgKDEgaW4gZWFjaCBvZiAyIGFtcGxpZmljYXRpb24gYmF0Y2hlcyksIGFuZCAxNTkgc2FtcGxlcyAoNTMgZmllbGQgc2FtcGxlcywgYW1wbGlmaWVkIGluIHRyaXBsaWNhdGUpLgoKIyMjIyAyLjUgQmlvaW5mb3JtYXRpY3MKCldlIHByb2Nlc3NlZCBzZXF1ZW5jaW5nIGRhdGEgdXNpbmcgdGhlIEFuYWNhcGEgVG9vbGtpdCwgd2hpY2ggY29udGFpbnMgdHdvIGNvcmUgbW9kdWxlczogb25lIGZvciBxdWFsaXR5IGNvbnRyb2wgYW5kIEFTViBwYXJzaW5nLCBhbmQgb25lIGZvciBjbGFzc2lmeWluZyB0YXhvbm9teSAoQ3VyZCBldCBhbC4sIDIwMTkpLiBCcmllZmx5LCB3ZSByYW4gdGhlIGZpcnN0IG1vZHVsZSB1c2luZyBkZWZhdWx0IHBhcmFtZXRlcnMsIHdoaWNoIHVzZXMgY3V0YWRhcHQgKHZlcnNpb24gMS4xNikgKE1hcnRpbiwgMjAxMSkgZm9yIGFkYXB0ZXIgYW5kIHByaW1lciB0cmltbWluZywgRmFzdFgtVG9vbGtpdCAodmVyc2lvbjogMC4wLjEzKSAoY2l0YXRpb24pIGZvciBxdWFsaXR5IHRyaW1taW5nLCBhbmQgZGFkYTIgKHZlcnNpb24gMS42KSAoQ2FsbGFoYW4gZXQgYWwuLCAyMDE2KSBmb3IgYXNzaWduaW5nIEFTVnMuIEZvciB0aGUgc2Vjb25kIG1vZHVsZSwgd2UgdXRpbGl6ZWQgdGhlIE1JRE9SSTIgcmVmZXJlbmNlIGRhdGFiYXNlLCBhIHF1YWxpdHkgY29udHJvbGxlZCBhbmQgdXBkYXRlZCBkYXRhYmFzZSBidWlsdCBmcm9tIEdlbkJhbmsgcmVsZWFzZSAyNTMgKDIwIERlY2VtYmVyIDIwMjIpIHRoYXQgaGFzIGJlZW4gdGVjaG5pY2FsbHkgdmFsaWRhdGVkIChMZXJheSBldCBhbC4sIDIwMjIpLiBGb2xsb3dpbmcgR29sZCBldCBhbC4gKDIwMjIpLCB3ZSBhZGp1c3RlZCB0aGUgaWRlbnRpdHkgYW5kIHF1ZXJ5IGNvdmVyYWdlIHRvIDk1JSAoZGVmYXVsdDogODAlKSB0byBhY2NvdW50IGZvciB0aGUgcmVsYXRpdmUgaW5jb21wbGV0ZW5lc3Mgb2YgdGhlIGJyb2FkIENPSSByZWZlcmVuY2UgZGF0YWJhc2UgY29tcGFyZWQgdG8gbW9yZSB0YXhvbm9taWNhbGx5LXNwZWNpZmljIGRhdGFiYXNlcyAoQ3VyZCBldCBhbC4sIDIwMTkpLiBUaGUgc2Vjb25kIG1vZHVsZSByZWxpZXMgb24gQm93dGllIDIgKHZlcnNpb24gMi4zLjUpIChMYW5nbWVhZCBhbmQgU2FsemJlcmcsIDIwMTIpIGFuZCBhIG1vZGlmaWVkIGluc3RhbmNlIG9mIEJMQ0EgKEdhbyBldCBhbC4sIDIwMTcpIGFzIGRlcGVuZGVuY2llcy4gRm9sbG93aW5nIEdvbGQgZXQgYWwuICgyMDIxYSkgd2Ugb25seSBrZXB0IHRheG9ub21pYyBhc3NpZ25tZW50cyB0aGF0IGhhZCBhIGJvb3RzdHJhcCBjb25maWRlbmNlIGN1dG9mZiBzY29yZSBvZiA2MCBvciBoaWdoZXIgaW4gQkxDQSwgdG8gYXZvaWQgc3B1cmlvdXMgYXNzaWdubWVudHMgZnJvbSB0aGUgaW5jb21wbGV0ZSByZWZlcmVuY2UgZGF0YWJhc2UuIFdlIG1vZGlmaWVkIHRoZSBBbmFjYXBhIENvbnRhaW5lciAoT2dkZW4sIDIwMTgpLCBhIFNpbmd1bGFyaXR5IGNvbnRhaW5lciB3aXRoIGFsbCB0aGUgbmVlZGVkIGRlcGVuZGVuY2llcyBmb3IgZXhlY3V0aW5nIHRoZSBBbmFjYXBhIFRvb2xraXQsIHRvIGVuYWJsZSB0aGUgcGlwZWxpbmUgdG8gYmUgcnVuIGluIGEgaGlnaC1wZXJmb3JtYW5jZSBjb21wdXRpbmcgZW52aXJvbm1lbnQgcmVxdWlyaW5nIHR3by1zdGVwIGF1dGhlbnRpY2F0aW9uOyB0aGUgdXBkYXRlZCBjb250YWluZXIsIHNjcmlwdHMsIGFuZCByZWZlcmVuY2UgZGF0YWJhc2Ugd2l0aCB0aGUgcmVxdWlyZWQgQm93dGllIDIgaW5kZXggbGlicmFyeSBuZWVkZWQgdG8gcmVwcm9kdWNlIG91ciBiaW9pbmZvcm1hdGljcyBwcm9jZXNzIGNhbiBiZSBmb3VuZCBvbiBEcnlhZCAobGluay9jaXRhdGlvbikuCgpSYXcgQVNWcywgdGF4b25vbXkgYXNzaWdubWVudHMsIGFuZCBtZXRhZGF0YSB3ZXJlIGNvbnZlcnRlZCBpbnRvIGludGVyY2hhbmdlYWJsZSBgYW1wdmlzMmAgKHZlcnNpb24gYHIgcGFja2FnZVZlcnNpb24oImFtcHZpczIiKWAgYHBhY2thZ2VWZXJzaW9uKCJhbXB2aXMyIilgKSAoQW5kZXJzZW4gZXQgYWwuLCAyMDE4KSBhbmQgYHBoeWxvc2VxYCAodmVyc2lvbiBgciBwYWNrYWdlVmVyc2lvbigicGh5bG9zZXEiKWAgYHBhY2thZ2VWZXJzaW9uKCJwaHlsb3NlcSIpYCkgKE1jTXVyZGllIGFuZCBIb2xtZXMsIDIwMTMpIG9iamVjdHMgaW4gYHIgUi5WZXJzaW9uKCkkdmVyc2lvbi5zdHJpbmdgIGBSLlZlcnNpb24oKSR2ZXJzaW9uLnN0cmluZ2AgdG8gZmFjaWxpdGF0ZSBkZWNvbnRhbWluYXRpb24gYW5kIGZ1cnRoZXIgYW5hbHlzZXMuIFNpbmdsZXRvbnMgd2VyZSByZW1vdmVkIHVzaW5nIGBhbXB2aXMyYCwgYW5kIHNhbXBsZXMgd2VyZSBmdXJ0aGVyIGRlY29udGFtaW5hdGVkIHVzaW5nIGBwaHlsb3NlcWAgYnkgcmVtb3ZpbmcgYWxsIEFTVnMgdGhhdCBhcHBlYXJlZCBpbiBhbnkgbmVnYXRpdmUgZmllbGQgY29udHJvbCwgbmVnYXRpdmUgZXh0cmFjdGlvbiBjb250cm9sLCBvciBuby10ZW1wbGF0ZSBuZWdhdGl2ZSBQQ1IgY29udHJvbCwgYSBjaG9pY2UgbWFkZSBkdWUgdG8gdGhlIHZlcnkgbG93IG51bWJlciBvZiBvdmVybGFwcGluZyBBU1ZzIGJldHdlZW4gc2FtcGxlcyBhbmQgbmVnYXRpdmUgY29udHJvbHMgKFRhYmxlIFMxKS4gU2FtcGxlcyB3ZXJlIHJhcmlmaWVkIHRvIHRoZSBtaW5pbXVtIG51bWJlciBvZiByZWFkcyBvZiBhbnkgc2FtcGxlIHVzaW5nIGBhbXB2aXMyYC4gU3Vic2VxdWVudCBhbmFseXNlcyB3ZXJlIHJvYnVzdCB0byBhbGwgdGhyZWUgZGVjb250YW1pbmF0aW9uIHN0ZXBzLgoKYGBge3IgSW1wb3J0aW5nIEFuYWNhcGEsIHdhcm5pbmcgPSBGQUxTRX0KIyMjSW1wb3J0aW5nIEFuYWNhcGEjIyMKI1JlYWQgaW4gQW5hY2FwYSBQaXBlbGluZSBPdXRwdXQgYW5kIHByb2Nlc3MgaW50byBhbXB2aXMyIG9iamVjdHMgZm9yIHVzZSBpbiBhbmFseXNlcwoKI1JlYWQgaW4gQW5hY2FwYSBPdXRwdXQKI0NoYW5nZSBwX2NvbmZpZGVuY2UgdG8gc3dpdGNoIHRvIGEgZGlmZmVyZW50IHBlcmNlbnQgY29uZmlkZW5jZSBvdXRwdXQKIyMjCnBfY29uZmlkZW5jZSA9IDYwCiMjIwpjdXJyZW50X3N1YmZvbGRlciA9ICJEYXRhL0FuYWNhcGEgUGlwZWxpbmUgT3V0cHV0L1RpZGUgUG9vbCA1MTg0IC0gMzEgSmFudWFyeSAyMDIzIgoKZmlsZXBhdGggPSBwYXN0ZTAoCiAgY3VycmVudF9zdWJmb2xkZXIsCiAgIi9DTzEvQ08xX3RheG9ub215X3RhYmxlcy9TdW1tYXJ5X2J5X3BlcmNlbnRfY29uZmlkZW5jZS8iLAogIHBfY29uZmlkZW5jZSwKICAiL0NPMV9BU1ZfcmF3X3RheG9ub215XyIsCiAgcF9jb25maWRlbmNlLAogICIudHh0IgopCgpBbmFjYXBhT3V0cHV0ID0gcmVhZC50YWJsZShmaWxlcGF0aCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjID0gIi4iKQoKI0Zvcm1hdCBBU1YgVGFibGUgKGV4dHJhY3QganVzdCB0aGUgbmVlZGVkIGluZm9ybWF0aW9uKQplbmRjb2wgPSBuY29sKEFuYWNhcGFPdXRwdXQpIC0gMQphc3ZtYXQgPSBBbmFjYXBhT3V0cHV0WywgMjplbmRjb2xdCnJvd25hbWVzKGFzdm1hdCkgPC0gQW5hY2FwYU91dHB1dFssIDFdCgojRm9ybWF0IFRheG9ub215IFRhYmxlIChleHRyYWN0IGp1c3QgdGhlIG5lZWRlZCBpbmZvcm1hdGlvbiBhbmQgcmVuYW1lIGNvbHVtbnMpCmVuZGNvbCA9IG5jb2woQW5hY2FwYU91dHB1dCkKdGF4bWF0ID0gQW5hY2FwYU91dHB1dFssIGVuZGNvbF0KdGF4bWF0ID0gc3RyX3NwbGl0X2ZpeGVkKHRheG1hdCwgIjsiLCA3KQpjb2xuYW1lcyh0YXhtYXQpIDwtCiAgYygiS2luZ2RvbSIsCiAgICAiUGh5bHVtIiwKICAgICJDbGFzcyIsCiAgICAiT3JkZXIiLAogICAgIkZhbWlseSIsCiAgICAiR2VudXMiLAogICAgIlNwZWNpZXMiKQpyb3duYW1lcyh0YXhtYXQpIDwtIHJvd25hbWVzKGFzdm1hdCkKCiNSZWFkIE1ldGFkYXRhIChzYXZlZCBpbiBtdWx0aXBsZSBkaWZmZXJlbnQgZmlsZXMpCgpjdXJyZW50X3N1YmZvbGRlciA9IHBhc3RlMChjdXJyZW50X3N1YmZvbGRlciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIi9NZXRhZGF0YS1BZGRlZC9QaWxsYXJQb2ludF9TYW1wbGVJbmZvXyIpCgpmaWxlcGF0aCA9IHBhc3RlMChjdXJyZW50X3N1YmZvbGRlciwgIkVudmlyb0RhdGEudHh0IikKRW52aXJvRGF0YSA9IHJlYWQudGFibGUoCiAgZmlsZXBhdGgsCiAgaGVhZGVyID0gVFJVRSwKICBzZXAgPSAiXHQiLAogIGRlYyA9ICIuIiwKICBzdHJpcC53aGl0ZSA9IFRSVUUKKQoKZmlsZXBhdGggPSBwYXN0ZTAoY3VycmVudF9zdWJmb2xkZXIsICJGaWVsZFNhbXBsaW5nLnR4dCIpCkZpZWxkU2FtcGxpbmcgPSByZWFkLnRhYmxlKAogIGZpbGVwYXRoLAogIGhlYWRlciA9IFRSVUUsCiAgc2VwID0gIlx0IiwKICBkZWMgPSAiLiIsCiAgc3RyaXAud2hpdGUgPSBUUlVFCikKRmllbGRTYW1wbGluZyA9IEZpZWxkU2FtcGxpbmdbLCAxOjRdCgpmaWxlcGF0aCA9IHBhc3RlMChjdXJyZW50X3N1YmZvbGRlciwgIlNlcXVlbmNpbmcudHh0IikKU2VxdWVuY2luZyA9IHJlYWQudGFibGUoCiAgZmlsZXBhdGgsCiAgaGVhZGVyID0gVFJVRSwKICBzZXAgPSAiXHQiLAogIGRlYyA9ICIuIiwKICBzdHJpcC53aGl0ZSA9IFRSVUUKKQoKZmlsZXBhdGggPSBwYXN0ZTAoY3VycmVudF9zdWJmb2xkZXIsICJMb2NhdGlvbi50eHQiKQpMb2NhdGlvbiA9IHJlYWQudGFibGUoCiAgZmlsZXBhdGgsCiAgaGVhZGVyID0gVFJVRSwKICBzZXAgPSAiXHQiLAogIGRlYyA9ICIuIiwKICBzdHJpcC53aGl0ZSA9IFRSVUUKKQoKI0Zvcm1hdCBNZXRhZGF0YQpzYW1wbGVkYXRhID0gbWVyZ2UoRmllbGRTYW1wbGluZywgRW52aXJvRGF0YSwgYWxsID0gVCkKc2FtcGxlZGF0YSA9IHNhbXBsZWRhdGEgJT4lIGRyb3BfbmEoRGVyZXBsaWNhdGVkX1NhbXBsZV9OYW1lKQojcmVtb3Zpbmcgb25lIHNhbXBsZSB0aGF0IGhhcyBFbnZpcm9EYXRhIHJlYWRpbmcgYnV0IHRoZSBmaWVsZCBzYW1wbGUgd2FzIG5vdCBwcm9jZXNzZWQKCnNhbXBsZWRhdGEgPSBtZXJnZShTZXF1ZW5jaW5nLCBzYW1wbGVkYXRhLCBhbGwgPSBUKQpyb3duYW1lcyhzYW1wbGVkYXRhKSA8LSBzYW1wbGVkYXRhWywgIlgiXQoKc2FtcGxlZGF0YSREZXJlcGxpY2F0ZWRfU2FtcGxlX05hbWUgPSBhcy5mYWN0b3Ioc2FtcGxlZGF0YSREZXJlcGxpY2F0ZWRfU2FtcGxlX05hbWUpCnNhbXBsZWRhdGEkVHlwZSA9IGFzLmZhY3RvcihzYW1wbGVkYXRhJFR5cGUpCnNhbXBsZWRhdGEkUENSID0gYXMuZmFjdG9yKHNhbXBsZWRhdGEkUENSKQpzYW1wbGVkYXRhJFRpbWUgPSBhcy5mYWN0b3Ioc2FtcGxlZGF0YSRUaW1lKQpzYW1wbGVkYXRhJExvY2F0aW9uID0gYXMuZmFjdG9yKHNhbXBsZWRhdGEkTG9jYXRpb24pCnNhbXBsZWRhdGEkRXh0cmFjdGlvbiA9IGFzLmZhY3RvcihzYW1wbGVkYXRhJEV4dHJhY3Rpb24pCnNhbXBsZWRhdGEkU2l0ZUJ5VGltZSA9IGFzLmZhY3RvcihwYXN0ZShzYW1wbGVkYXRhJExvY2F0aW9uLCBzYW1wbGVkYXRhJFRpbWUpKQoKI01ha2UgYW1wdmlzMiBvYmplY3RzIHdpdGhvdXQgYW55IHByZS1wcm9jZXNzaW5nCmFzdm1hdF9hbXAgPSB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbihhc3ZtYXQsICJBU1YiKQpzYW1wbGVkYXRhX2FtcCA9IHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKHNhbXBsZWRhdGEsICJTYW1wbGUiKQp0YXhtYXRfYW1wID0gdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oYXMuZGF0YS5mcmFtZSh0YXhtYXQpLCAiQVNWIikKYW1wID0gYW1wX2xvYWQoYXN2bWF0X2FtcCwgbWV0YWRhdGEgPSBzYW1wbGVkYXRhX2FtcCwgdGF4b25vbXkgPSB0YXhtYXRfYW1wKQoKYW1wX25vY29udHJvbHMgPSBhbXBfZmlsdGVyX3NhbXBsZXMoYW1wLCBUeXBlICVpbiUgYygic2FtcGxlIikpCmFtcF9jb250cm9scyA9IGFtcF9maWx0ZXJfc2FtcGxlcyhhbXAsIFR5cGUgJWluJSBjKCJjb250cm9sIikpCgojTWFrZSBhbXB2aXMyIG9iamVjdHMgd2l0aCBzaW5nbGV0b25zIHJlbW92ZWQKYW1wX05TID0gYW1wX2xvYWQoCiAgYXN2bWF0X2FtcCwKICBtZXRhZGF0YSA9IHNhbXBsZWRhdGFfYW1wLAogIHRheG9ub215ID0gdGF4bWF0X2FtcCwKICBwcnVuZVNpbmdsZXRvbnMgPSBUUlVFCikKCmFtcF9ub2NvbnRyb2xzX05TID0gYW1wX2ZpbHRlcl9zYW1wbGVzKGFtcF9OUywgVHlwZSAlaW4lIGMoInNhbXBsZSIpKQphbXBfY29udHJvbHNfTlMgPSBhbXBfZmlsdGVyX3NhbXBsZXMoYW1wX05TLCBUeXBlICVpbiUgYygiY29udHJvbCIpKQoKI01ha2UgYW1wdmlzMiBvYmplY3RzIHdpdGggYSBmdWxsIGRlY29udGFtaW5hdGlvbiBwcm9jZWR1cmUKCiNGdW5jdGlvbiB0aGF0IHJlbW92ZXMgYW55IEFTViB0aGF0IGFwcGVhcnMgaW4gYW55IGNvbnRyb2wgZnJvbSBhbGwgc2FtcGxlcwpmdWxsX2RlY29udGFtaW5hdGlvbiA8LSBmdW5jdGlvbihhbXApIHsKICBwaHlzZXEgPSBhbXBfdG9fcGh5bG9zZXEoYW1wLCBOVUxMLCBOVUxMLCBOVUxMKQogIAogIHBoeXNlcV9jb250cm9scyA8LSBwaHlzZXEgJT4lCiAgICBzdWJzZXRfc2FtcGxlcyhUeXBlID09ICJjb250cm9sIikgJT4lCiAgICBwcnVuZV90YXhhKHRheGFfc3VtcyguKSA+IDAsIC4pCiAgCiAgYmFkQVNWID0gdGF4YV9uYW1lcyhwaHlzZXFfY29udHJvbHMpCiAgYWxsQVNWID0gdGF4YV9uYW1lcyhwaHlzZXEpCiAgYWxsQVNWIDwtIGFsbEFTVlshKGFsbEFTViAlaW4lIGJhZEFTVildCiAgcGh5c2VxX0ZEID0gcHJ1bmVfdGF4YShhbGxBU1YsIHBoeXNlcSkKICAKICBhdjJfb3R1dGFibGUgPC0gZGF0YS5mcmFtZShvdHVfdGFibGUocGh5c2VxX0ZEKUAuRGF0YSkKICBhdjJfdGF4dGFibGUgPC0gZGF0YS5mcmFtZSh0YXhfdGFibGUocGh5c2VxX0ZEKUAuRGF0YSkKICBhdjJfbWV0YWRhdGEgPC0gZGF0YS5mcmFtZShzYW1wbGVfZGF0YShwaHlzZXFfRkQpKQogIAogIGFtcF9yZXR1cm4gPC0KICAgIGFtcF9sb2FkKGF2Ml9vdHV0YWJsZSwgbWV0YWRhdGEgPSBhdjJfbWV0YWRhdGEsIHRheG9ub215ID0gYXYyX3RheHRhYmxlKQogIGFtcF9yZXR1cm4gPSBhbXBfZmlsdGVyX3NhbXBsZXMoYW1wX3JldHVybiwgVHlwZSAlaW4lIGMoInNhbXBsZSIpKQogIAogIHJldHVybihhbXBfcmV0dXJuKQp9CgphbXBfbm9jb250cm9sc19GRCA9IGZ1bGxfZGVjb250YW1pbmF0aW9uKGFtcCkKYW1wX25vY29udHJvbHNfTlNfRkQgPSBmdWxsX2RlY29udGFtaW5hdGlvbihhbXBfTlMpCgojTWFrZSBhbXB2aXMyIG9iamVjdHMgYnkgcmFyZWZ5aW5nIHRvIHRoZSBtaW5pbXVtIG51bWJlciBvZiByZWFkcyBvZiBhbnkgc2FtcGxlCgojRnVuY3Rpb24gdGhhdCB3cmFwcyBhcm91bmQgYW4gYW1wdmlzMiBmdW5jdGlvbiB0byByYXJlZnkgc2FtcGxlcyB0byB0aGUgbWluaW11bSBudW1iZXIgb2YgcmVhZHMgb2YgYW55IHNhbXBsZQpyYXJlZmFjdGlvbiA8LSBmdW5jdGlvbihhbXApIHsKICBzZXQuc2VlZCgwKQogIHJlYWRzIDwtIGNvbFN1bXMoYW1wJGFidW5kKQogIG1pbnJlYWRzIDwtIG1pbihyZWFkcykKICBhbXBfUiA9IGFtcF9zdWJzZXRfc2FtcGxlcyhhbXAsIHJhcmVmeSA9IG1pbnJlYWRzKQogIHJldHVybihhbXBfUikKfQoKYW1wX25vY29udHJvbHNfUiA9IHJhcmVmYWN0aW9uKGFtcF9ub2NvbnRyb2xzKQphbXBfbm9jb250cm9sc19OU19SID0gcmFyZWZhY3Rpb24oYW1wX25vY29udHJvbHNfTlMpCmFtcF9ub2NvbnRyb2xzX0ZEX1IgPSByYXJlZmFjdGlvbihhbXBfbm9jb250cm9sc19GRCkKYW1wX25vY29udHJvbHNfTlNfRkRfUiA9IHJhcmVmYWN0aW9uKGFtcF9ub2NvbnRyb2xzX05TX0ZEKQpgYGAKCmBgYHtyIE1ha2luZyBOQ0JJIERhdGEgRnJhbWVzLCB3YXJuaW5nID0gRkFMU0V9CiMjI01ha2luZyBOQ0JJIERhdGEgRnJhbWVzIyMjCiMjQ3JlYXRlIGRhdGEgZnJhbWVzIGZvciBzdWJtaXNzaW9uIHRvIE5DQkkgU1JBIGJhc2VkIG9uIHJlcXVpcmVkIGluZm9ybWF0aW9uIGluIEJpb1NhbXBsZSBwYWNrYWdlIE1JTUFSS1M6IHN1cnZleSwgd2F0ZXI7IHZlcnNpb24gNi4wIGFzIHdlbGwgYXMgYWRkaXRpb25hbCBzdWdnZXN0ZWQgZGV0YWlsZWQgZnJvbSB0aGUgTk9BQSBPbWljcyBEYXRhIE1hbmFnZW1lbnQgR3VpZGUgKGh0dHBzOi8vbm9hYS1vbWljcy1kbWcucmVhZHRoZWRvY3MuaW8vZW4vbGF0ZXN0L2NvbnRyaWJ1dG9ycy5odG1sKQoKIyNCaW9TYW1wbGUgYXR0cmlidXRlcwoKTkNCSV9leHBvcnQgPSBtZXJnZShhbXAkbWV0YWRhdGEsIExvY2F0aW9uLCBhbGwgPSBUKQoKI0xhdGl0dWRlICsgTG9uZ2l0dWRlCmxhdF9sb24gPSBkby5jYWxsKHBhc3RlLCBsaXN0KAogIE5DQklfZXhwb3J0JExhdGl0dWRlLAogICJOIiwKICBnc3ViKCItIiwgIiIsIE5DQklfZXhwb3J0JExvbmdpdHVkZSksCiAgIlciLAogIHNlcCA9ICIgIgopKQpsYXRfbG9uW2xhdF9sb24gPT0gIk5BIE4gTkEgVyJdID0gIk5BIgpOQ0JJX2V4cG9ydCA9IGNiaW5kKE5DQklfZXhwb3J0LCBsYXRfbG9uKQoKI0RhdGUgYW5kIHRpbWUKRGF0ZSA9ICIyMDIyLTAxLTI4IgpOQ0JJX2V4cG9ydCA9IGNiaW5kKE5DQklfZXhwb3J0LCBEYXRlKQoKTkNCSV9leHBvcnQkY29sbGVjdGlvbl9kYXRlX2xvY2FsIDwtCiAgbHVicmlkYXRlOjp5bWRfaG0ocGFzdGUoTkNCSV9leHBvcnQkRGF0ZSwgIlQiLCBOQ0JJX2V4cG9ydCRUaW1lKSwgdHogPSAiVVMvUGFjaWZpYyIpCgpOQ0JJX2V4cG9ydCRjb2xsZWN0aW9uX2RhdGUgPC0KICB3aXRoX3R6KE5DQklfZXhwb3J0JGNvbGxlY3Rpb25fZGF0ZV9sb2NhbCwgIlp1bHUiKQoKWnVsdSA8LSBzdGFtcCgiMjAyMC0wNC0wNFQxODowNTowMFoiKQpOQ0JJX2V4cG9ydCRjb2xsZWN0aW9uX2RhdGUgPSBadWx1KE5DQklfZXhwb3J0JGNvbGxlY3Rpb25fZGF0ZSkKClBTVCA8LSBzdGFtcCgiMjAyMC0wNC0wNFQxODowNTowMFBTVCIpCk5DQklfZXhwb3J0JGNvbGxlY3Rpb25fZGF0ZV9sb2NhbCA9IFBTVChOQ0JJX2V4cG9ydCRjb2xsZWN0aW9uX2RhdGVfbG9jYWwpCgojUmVuYW1lIGNvbHVtbnMKTkNCSV9leHBvcnQgPSBOQ0JJX2V4cG9ydFtjKAogICJTYW1wbGUiLAogICJTYW1wbGVfTmFtZSIsCiAgIlR5cGUiLAogICJMb2NhdGlvbiIsCiAgIlQiLAogICJTIiwKICAiQ1JTIiwKICAibGF0X2xvbiIsCiAgImNvbGxlY3Rpb25fZGF0ZSIsCiAgImNvbGxlY3Rpb25fZGF0ZV9sb2NhbCIKKV0KTkNCSV9leHBvcnQgPSBOQ0JJX2V4cG9ydCAlPiUgcmVuYW1lKAogIHNhbXBsZV9uYW1lID0gU2FtcGxlLAogIHNhbXBsZV90aXRsZSA9IFNhbXBsZV9OYW1lLAogIHNhbXBsZV9jb250cm9sID0gVHlwZSwKICBzYWxpbml0eSA9IFMsCiAgdGVtcGVyYXR1cmUgPSBULAogIGdlb2RldGljRGF0dW0gPSBDUlMKKQoKTkNCSV9leHBvcnQkdW5pcXVlX3NhbXBsZV9pZGVudGlmaWVyID0gTkNCSV9leHBvcnQkc2FtcGxlX3RpdGxlCgojQWRkIHVuaXRzIHRvIHRlbXBlcmF0dXJlICYgc2FsaW5pdHkKTkNCSV9leHBvcnQkdGVtcGVyYXR1cmVbIWlzLm5hKE5DQklfZXhwb3J0JHRlbXBlcmF0dXJlKV0gPSBwYXN0ZShOQ0JJX2V4cG9ydCR0ZW1wZXJhdHVyZVshaXMubmEoTkNCSV9leHBvcnQkdGVtcGVyYXR1cmUpXSwgIsKwQyIsIHNlcCA9ICIgIikKTkNCSV9leHBvcnQkc2FsaW5pdHlbIWlzLm5hKE5DQklfZXhwb3J0JHNhbGluaXR5KV0gPSBwYXN0ZShOQ0JJX2V4cG9ydCRzYWxpbml0eVshaXMubmEoTkNCSV9leHBvcnQkc2FsaW5pdHkpXSwgInBwdCIsIHNlcCA9ICIgIikKCiNEZXB0aApkZXB0aCA9IGMoKQpkZXB0aFtOQ0JJX2V4cG9ydCRzYW1wbGVfY29udHJvbCA9PSAiY29udHJvbCJdID0gIk5BIgpkZXB0aFtOQ0JJX2V4cG9ydCRzYW1wbGVfY29udHJvbCA9PSAic2FtcGxlIl0gPSAiU3VyZmFjZSIKTkNCSV9leHBvcnQgPSBjYmluZChOQ0JJX2V4cG9ydCwgZGVwdGgpCgojU2l6ZSBmcmFjdGlvbgpzaXplX2ZyYWMgPSBjKCkKc2l6ZV9mcmFjW05DQklfZXhwb3J0JHNhbXBsZV9jb250cm9sID09ICJjb250cm9sIl0gPSAiTkEiCnNpemVfZnJhY1tOQ0JJX2V4cG9ydCRzYW1wbGVfY29udHJvbCA9PSAic2FtcGxlIl0gPSAiMC4yMiBtaWNyb21ldGVyIgpzaXplX2ZyYWNbTkNCSV9leHBvcnQkTG9jYXRpb24gPT0gIkZCIl0gPSAiMC4yMiBtaWNyb21ldGVyIgpOQ0JJX2V4cG9ydCA9IGNiaW5kKE5DQklfZXhwb3J0LCBzaXplX2ZyYWMpCgojU2FtcGxlIHZvbHVtZQpzYW1wX3ZvbF93ZV9kbmFfZXh0ID0gYygpCnNhbXBfdm9sX3dlX2RuYV9leHRbTkNCSV9leHBvcnQkc2FtcGxlX2NvbnRyb2wgPT0gImNvbnRyb2wiXSA9ICJOQSIKc2FtcF92b2xfd2VfZG5hX2V4dFtOQ0JJX2V4cG9ydCRzYW1wbGVfY29udHJvbCA9PSAic2FtcGxlIl0gPSAiMTAwMCBtTCIKc2FtcF92b2xfd2VfZG5hX2V4dFtOQ0JJX2V4cG9ydCRMb2NhdGlvbiA9PSAiRkIiXSA9ICIxMDAwIG1MIgpOQ0JJX2V4cG9ydCA9IGNiaW5kKE5DQklfZXhwb3J0LCBzYW1wX3ZvbF93ZV9kbmFfZXh0KQoKI09yZ2FuaXNtCm9yZ2FuaXNtID0gYygpCm9yZ2FuaXNtW05DQklfZXhwb3J0JHNhbXBsZV9jb250cm9sID09ICJzYW1wbGUiXSA9ICJzZWF3YXRlciBtZXRhZ2Vub21lIgpvcmdhbmlzbVtOQ0JJX2V4cG9ydCRMb2NhdGlvbiA9PSAiTUMiXSA9ICJzeW50aGV0aWMgbWV0YWdlbm9tZSIKb3JnYW5pc21bTkNCSV9leHBvcnQkTG9jYXRpb24gPT0gIkVCIl0gPSAibWV0YWdlbm9tZSIKb3JnYW5pc21bTkNCSV9leHBvcnQkTG9jYXRpb24gPT0gIkZCIl0gPSAibWV0YWdlbm9tZSIKb3JnYW5pc21bTkNCSV9leHBvcnQkTG9jYXRpb24gPT0gIk5UQyJdID0gIm1ldGFnZW5vbWUiCk5DQklfZXhwb3J0ID0gY2JpbmQoTkNCSV9leHBvcnQsIG9yZ2FuaXNtKQoKI0Vudmlyb25tZW50YWwgQ29udGV4dAplbnZfYnJvYWRfc2NhbGUgPSBjKCkKZW52X2Jyb2FkX3NjYWxlW05DQklfZXhwb3J0JHNhbXBsZV9jb250cm9sID09ICJzYW1wbGUiXSA9ICJtYXJpbmUgYmlvbWUgW0VOVk86MDAwMDA0NDddIgpOQ0JJX2V4cG9ydCA9IGNiaW5kKE5DQklfZXhwb3J0LCBlbnZfYnJvYWRfc2NhbGUpCgplbnZfbG9jYWxfc2NhbGUgPSBjKCkKZW52X2xvY2FsX3NjYWxlW05DQklfZXhwb3J0JHNhbXBsZV9jb250cm9sID09ICJzYW1wbGUiXSA9ICJzaG9yZWxpbmUgW0VOVk86MDAwMDA0ODZdfGludGVydGlkYWwgem9uZSBbRU5WTzowMDAwMDMxNl0iCk5DQklfZXhwb3J0ID0gY2JpbmQoTkNCSV9leHBvcnQsIGVudl9sb2NhbF9zY2FsZSkKCmVudl9tZWRpdW0gPSBjKCkKZW52X21lZGl1bVtOQ0JJX2V4cG9ydCRzYW1wbGVfY29udHJvbCA9PSAic2FtcGxlIl0gPSAiY29hc3RhbCBzZWEgd2F0ZXIgW0VOVk9fMDAwMDIxNTBdIgpOQ0JJX2V4cG9ydCA9IGNiaW5kKE5DQklfZXhwb3J0LCBlbnZfbWVkaXVtKQoKZ2VvX2xvY19uYW1lID0gYygpCmdlb19sb2NfbmFtZVtOQ0JJX2V4cG9ydCRzYW1wbGVfY29udHJvbCA9PSAic2FtcGxlIl0gPSAiVVNBOiBDYWxpZm9ybmlhLCBIYWxmIE1vb24gQmF5LCBQaWxsYXIgUG9pbnQsIEludGVydGlkYWwiCk5DQklfZXhwb3J0ID0gY2JpbmQoTkNCSV9leHBvcnQsIGdlb19sb2NfbmFtZSkKCiNTYW1wbGluZyBNZXRob2RzCnNhbXBfbWF0X3Byb2Nlc3MgPSBjKCkKc2FtcF9tYXRfcHJvY2Vzc1tOQ0JJX2V4cG9ydCRzYW1wbGVfY29udHJvbCA9PSAic2FtcGxlIl0gPSAiR3Jhdml0eSBmaWx0ZXJlZCB0aHJvdWdoIFN0ZXJpdmV4ICgwLjIyLcK1bSk6IGR4LmRvaS5vcmcvMTAuMTc1MDQvcHJvdG9jb2xzLmlvLmJwMmw2OXk3a2xxZS92MiIKc2FtcF9tYXRfcHJvY2Vzc1tOQ0JJX2V4cG9ydCRMb2NhdGlvbiA9PSAiTUMiXSA9ICJNb2NrIGNvbW11bml0eSBmcm9tIGVxdWltb2xhciBjb21iaW5hdGlvbiBvZiA1IHRpc3VlIEROQSBleHRyYWN0aW9uOiBNeXRpbHVzIGVkdWxpcywgTWl6dWhvcGVjdGVuIHllc3NvZW5zaXMsIFhpcGhpYXMgZ2xhZGl1cywgTWVyY2VuYXJpYSBtZXJjZW5hcmlhLCBMdXRqYW51cyBjYW1wZWNoYW51cyIKc2FtcF9tYXRfcHJvY2Vzc1tOQ0JJX2V4cG9ydCRMb2NhdGlvbiA9PSAiRUIiXSA9ICJETkEgZXh0cmFjdGlvbiBmcm9tIGEgc3RlcmlsZSBTdGVyaXZleDogZHguZG9pLm9yZy8xMC4xNzUwNC9wcm90b2NvbHMuaW8uZXdvdjFxeXl5Z3IyL3YxIgpzYW1wX21hdF9wcm9jZXNzW05DQklfZXhwb3J0JExvY2F0aW9uID09ICJGQiJdID0gIkdyYXZpdHkgZmlsdGVyZWQgdGhyb3VnaCBTdGVyaXZleCAoMC4yMi3CtW0pOiBkeC5kb2kub3JnLzEwLjE3NTA0L3Byb3RvY29scy5pby5icDJsNjl5N2tscWUvdjIiCnNhbXBfbWF0X3Byb2Nlc3NbTkNCSV9leHBvcnQkTG9jYXRpb24gPT0gIk5UQyJdID0gIlBDUiBuby10ZW1wbGF0ZSBjb250cm9sIGZvciBmaXJzdCBQQ1IgcmVhY3Rpb246IGR4LmRvaS5vcmcvMTAuMTc1MDQvcHJvdG9jb2xzLmlvLmRtNmdwM3dwZHZ6cC92MSIKTkNCSV9leHBvcnQgPSBjYmluZChOQ0JJX2V4cG9ydCwgc2FtcF9tYXRfcHJvY2VzcykKCnNhbXBfY29sbGVjdF9kZXZpY2UgPSBjKCkKc2FtcF9jb2xsZWN0X2RldmljZVtOQ0JJX2V4cG9ydCRzYW1wbGVfY29udHJvbCA9PSAic2FtcGxlIl0gPSAiQ292aWRpZW4gc2luZ2xlLXVzZSBlbnRlcmFsIGZlZWRpbmcgcG91Y2giCnNhbXBfY29sbGVjdF9kZXZpY2VbTkNCSV9leHBvcnQkTG9jYXRpb24gPT0gIkZCIl0gPSAiQ292aWRpZW4gc2luZ2xlLXVzZSBlbnRlcmFsIGZlZWRpbmcgcG91Y2giCk5DQklfZXhwb3J0ID0gY2JpbmQoTkNCSV9leHBvcnQsIHNhbXBfY29sbGVjdF9kZXZpY2UpCgphbXBsaWNvbl9zZXF1ZW5jZWQgPSAiQ09JIgpOQ0JJX2V4cG9ydCA9IGNiaW5kKE5DQklfZXhwb3J0LCBhbXBsaWNvbl9zZXF1ZW5jZWQpCgpOQ0JJX2V4cG9ydCRzYW1wbGVfdGl0bGVbTkNCSV9leHBvcnQkc2FtcGxlX2NvbnRyb2wgPT0gInNhbXBsZSJdID0gcGFzdGUoIlBpbGxhciBQb2ludCBpbnRlcnRpZGFsIHNlYXdhdGVyIHNhbXBsZSIsIE5DQklfZXhwb3J0JHNhbXBsZV90aXRsZVtOQ0JJX2V4cG9ydCRzYW1wbGVfY29udHJvbCA9PSAic2FtcGxlIl0sIHNlcCA9ICIgIikKCk5DQklfZXhwb3J0JHNhbXBsZV90aXRsZVtOQ0JJX2V4cG9ydCRMb2NhdGlvbiA9PSAiRUIiXSA9IHBhc3RlKCJFeHRyYWN0aW9uIGJsYW5rIiwgTkNCSV9leHBvcnQkc2FtcGxlX3RpdGxlW05DQklfZXhwb3J0JExvY2F0aW9uID09ICJFQiJdLCBzZXAgPSAiICIpCgpOQ0JJX2V4cG9ydCRzYW1wbGVfdGl0bGVbTkNCSV9leHBvcnQkTG9jYXRpb24gPT0gIkZCIl0gPSBwYXN0ZSgiTWlsbGlRIHdhdGVyIGZpZWxkIGJsYW5rIiwgTkNCSV9leHBvcnQkc2FtcGxlX3RpdGxlW05DQklfZXhwb3J0JExvY2F0aW9uID09ICJGQiJdLCBzZXAgPSAiICIpCgpOQ0JJX2V4cG9ydCRzYW1wbGVfdGl0bGVbTkNCSV9leHBvcnQkTG9jYXRpb24gPT0gIk5UQyJdID0gcGFzdGUoIlBDUiBuby10ZW1wbGF0ZSBjb250cm9sIiwgTkNCSV9leHBvcnQkc2FtcGxlX3RpdGxlW05DQklfZXhwb3J0JExvY2F0aW9uID09ICJOVEMiXSwgc2VwID0gIiAiKQoKTkNCSV9leHBvcnQkc2FtcGxlX3RpdGxlW05DQklfZXhwb3J0JExvY2F0aW9uID09ICJNQyJdID0gcGFzdGUoIkN1c3RvbSBtb2NrIGNvbW11bml0eSBzYW1wbGUiLCBOQ0JJX2V4cG9ydCRzYW1wbGVfdGl0bGVbTkNCSV9leHBvcnQkTG9jYXRpb24gPT0gIk1DIl0sIHNlcCA9ICIgIikKCiNTYW1wbGUgU3RvcmFnZQpzYW1wbGVfc3RvcmFnZV9kdXJhdGlvbiA9IGMoKQpzYW1wbGVfc3RvcmFnZV9kdXJhdGlvbltOQ0JJX2V4cG9ydCRzYW1wbGVfY29udHJvbCA9PSAic2FtcGxlIl0gPSAiMTggZGF5cyIKc2FtcGxlX3N0b3JhZ2VfZHVyYXRpb25bTkNCSV9leHBvcnQkTG9jYXRpb24gPT0gIkZCIl0gPSAiMTggZGF5cyIKTkNCSV9leHBvcnQgPSBjYmluZChOQ0JJX2V4cG9ydCwgc2FtcGxlX3N0b3JhZ2VfZHVyYXRpb24pCgpzYW1wbGVfc3RvcmFnZV9sb2NhdGlvbiA9IGMoKQpzYW1wbGVfc3RvcmFnZV9sb2NhdGlvbltOQ0JJX2V4cG9ydCRzYW1wbGVfY29udHJvbCA9PSAic2FtcGxlIl0gPSAiU3RhbmZvcmQgWTJFMiBCdWlsZGluZywgRW52aXJvbm1lbnRhbCBFbmdpbmVlcmluZyBhbmQgU2NpZW5jZSBMYWIsIFdhbGstSW4gLTIwIMKwQyBGcmVlemVyIgpzYW1wbGVfc3RvcmFnZV9sb2NhdGlvbltOQ0JJX2V4cG9ydCRMb2NhdGlvbiA9PSAiRkIiXSA9ICJTdGFuZm9yZCBZMkUyIEJ1aWxkaW5nLCBFbnZpcm9ubWVudGFsIEVuZ2luZWVyaW5nIGFuZCBTY2llbmNlIExhYiwgV2Fsay1JbiAtMjAgwrBDIEZyZWV6ZXIiCk5DQklfZXhwb3J0ID0gY2JpbmQoTkNCSV9leHBvcnQsIHNhbXBsZV9zdG9yYWdlX2xvY2F0aW9uKQoKc2FtcGxlX3N0b3JhZ2VfdGVtcGVyYXR1cmUgPSBjKCkKc2FtcGxlX3N0b3JhZ2VfdGVtcGVyYXR1cmVbTkNCSV9leHBvcnQkc2FtcGxlX2NvbnRyb2wgPT0gInNhbXBsZSJdID0gIi0yMCDCsEMiCnNhbXBsZV9zdG9yYWdlX3RlbXBlcmF0dXJlW05DQklfZXhwb3J0JExvY2F0aW9uID09ICJGQiJdID0gIi0yMCDCsEMiCk5DQklfZXhwb3J0ID0gY2JpbmQoTkNCSV9leHBvcnQsIHNhbXBsZV9zdG9yYWdlX3RlbXBlcmF0dXJlKQoKCk5DQklfZXhwb3J0ID0gTkNCSV9leHBvcnQgJT4lIHJlbmFtZShzcGVjaWZpY19pbnRlcnRpZGFsX2xvY2F0aW9uID0gTG9jYXRpb24pCk5DQklfZXhwb3J0JHNwZWNpZmljX2ludGVydGlkYWxfbG9jYXRpb24gPSBhcy5jaGFyYWN0ZXIoTkNCSV9leHBvcnQkc3BlY2lmaWNfaW50ZXJ0aWRhbF9sb2NhdGlvbikKTkNCSV9leHBvcnQkc3BlY2lmaWNfaW50ZXJ0aWRhbF9sb2NhdGlvbltOQ0JJX2V4cG9ydCRzYW1wbGVfY29udHJvbCA9PSAiY29udHJvbCJdID0gIk5BIgoKTkNCSV9leHBvcnRbaXMubmEoTkNCSV9leHBvcnQpXSA8LSAibm90IGFwcGxpY2FibGUiCk5DQklfZXhwb3J0W05DQklfZXhwb3J0ID09ICJOQSJdIDwtICJub3QgYXBwbGljYWJsZSIKCiMjU1JBIE1ldGFkYXRhCgpTUkFfbWV0YWRhdGEgPSBOQ0JJX2V4cG9ydFtjKCJzYW1wbGVfbmFtZSIsICJ1bmlxdWVfc2FtcGxlX2lkZW50aWZpZXIiKV0KU1JBX21ldGFkYXRhID0gU1JBX21ldGFkYXRhICU+JSByZW5hbWUobGlicmFyeV9JRCA9IHVuaXF1ZV9zYW1wbGVfaWRlbnRpZmllcikKClNSQV9tZXRhZGF0YSR0aXRsZSA9ICJDT0kgYW1wbGljb24gbWV0YWJhcmNvZGluZyBvZiBzZWF3YXRlciBmb3IgbWFyaW5lIG1ldGF6b2E6IFBpbGxhciBQb2ludCwgSGFsZiBNb29uIEJheSwgQ0EgKFVTQSkiCgpTUkFfbWV0YWRhdGEkbGlicmFyeV9zdHJhdGVneSA9ICJBTVBMSUNPTiIKU1JBX21ldGFkYXRhJGxpYnJhcnlfc291cmNlID0gIk1FVEFHRU5PTUlDIgpTUkFfbWV0YWRhdGEkbGlicmFyeV9zZWxlY3Rpb24gPSAiUENSIgpTUkFfbWV0YWRhdGEkbGlicmFyeV9sYXlvdXQgPSAicGFpcmVkIgpTUkFfbWV0YWRhdGEkcGxhdGZvcm0gPSAiSUxMVU1JTkEiClNSQV9tZXRhZGF0YSRpbnN0cnVtZW50X21vZGVsID0gIklsbHVtaW5hIE1pU2VxIgpTUkFfbWV0YWRhdGEkZGVzaWduX2Rlc2NyaXB0aW9uID0gIldhdGVyIHNhbXBsZXMgd2VyZSBncmF2aXR5IGZpbHRlcmVkIG9udG8gU3Rlcml2ZXggMC4yMiDCtW0gZmlsdGVyIGNhcnRyaWRnZXMgKGR4LmRvaS5vcmcvMTAuMTc1MDQvcHJvdG9jb2xzLmlvLmJwMmw2OXk3a2xxZS92MikuIEROQSB3YXMgZXh0cmFjdGVkIHVzaW5nIGEgbW9kaWZpZWQgdmVyc2lvbiBvZiB0aGUgRE5lYXN5IEJsb29kIGFuZCBUaXNzdWUgS2l0IChRaWFnZW4sIEdlcm1hbnRvd24sIE1ELCBVU0EpLCBpbiBtZXRob2RzIGRlc2NyaWJlZCBoZXJlIChkeC5kb2kub3JnLzEwLjE3NTA0L3Byb3RvY29scy5pby5ld292MXF5eXlncjIvdjEpLiBTYW1wbGVzIHdlcmUgUENSIGFtcGxpZmllZCB1c2luZyB0aGUgbWxDT0lpbnRGLyBqZ0hDTzIxOTggcHJpbWVyIHNldCB0YXJnZXRpbmcgYSAzMTMgYnAgZnJhZ21lbnQgb2YgdGhlIG1pdG9jaG9uZHJpYWwgQ09JIHJlZ2lvbiBvcHRpbWl6ZWQgYnkgTGVyYXkgZXQgYWwuICgyMDEzKSAoRm9yd2FyZDogR0dXQUNXR0dXVEdBQUNXR1RXVEFZQ0NZQ0M7IFJldmVyc2U6IFRBSUFDWVRDSUdHUlRHSUNDUkFBUkFBWUNBKSB3aXRoIE5leHRlcmEgbW9kaWZpY2F0aW9ucy4gRnVsbCBQQ1IgbWV0aG9kcyBjYW4gYmUgZm91bmQgaGVyZSAoZHguZG9pLm9yZy8xMC4xNzUwNC9wcm90b2NvbHMuaW8uZG02Z3Azd3BkdnpwL3YxKS4gUENSIHByb2R1Y3RzIHdlcmUgc2VudCBmb3IgbGlicmFyeSBwcmVwYXJhdGlvbiBhbmQgc2VxdWVuY2luZyBhdCB0aGUgR2VvcmdpYSBHZW5vbWljcyBhbmQgQmlvaW5mb3JtYXRpY3MgQ29yZSAoR0dCQywgVUcgQXRoZW5zLCBHQSwgUlJJRDpTQ1JfMDEwOTk0KS4gSW4gc2hvcnQsIHByb3ZpZGVkIFBDUiBhbXBsaWNvbnMgd2VyZSBjbGVhbmVkIHVzaW5nIEFNUHVyZSBYUCBtYWduZXRpYyBiZWFkcyAoQmVja21hbiBDb3VsdGVyLCBJbmRpYW5hcG9saXMsIElOLCBVU0EpLCBiYXJjb2RlZCB3aXRoIE5leHRlcmEgYWRhcHRlcnMgKElsbHVtaW5hLCBTYW4gRGllZ28sIENBLCBVU0EpIGR1cmluZyBhIHNlY29uZCBQQ1IgKDMgbWluIGF0IDk1IMKwQzsgMTUgY3ljbGVzIG9mIDMwIHNlYyBhdCA5NSDCsEMsIDMwIHNlYyBhdCA2NyDCsEMsIGFuZCAzMCBzZWMgYXQgNzIgwrBDOyBhbmQgNCBtaW4gYXQgNzIgwrBDKSwgY2xlYW5lZCBhZ2FpbiB1c2luZyBBTVB1cmVYUCBtYWduZXRpYyBiZWFkcywgYW5kIHBvb2xlZCBpbiBlcXVpbW9sYXIgcmF0aW8uIFRoZSByZXN1bHRpbmcgbGlicmFyeSB3YXMgc2VxdWVuY2VkIG9uIGEgTWlTZXEgUEUgMngyNTBicCAoNTAwIGN5Y2xlcykgdXNpbmcgUmVhZ2VudCBLaXQgVjIgd2l0aCAyNSUgUGhpWCBzcGlrZS1pbiAoSWxsdW1pbmEsIFNhbiBEaWVnbywgQ0EsIFVTQSkuIgpTUkFfbWV0YWRhdGEkZmlsZXR5cGUgPSAiZmFzdHEiCgpmaWxlbmFtZSA9IGdzdWIoIi4qXyIsICIiLCBTUkFfbWV0YWRhdGEkc2FtcGxlX25hbWUpCmZpbGVuYW1lID0gc3ViKCJcXC5MMDAxIiwgIl9MMDAxIiwgZmlsZW5hbWUpCmZpbGVuYW1lID0gc3ViKCJcXC5TIiwgIl9TIiwgZmlsZW5hbWUpCmZpbGVuYW1lID0gZ3N1YigiXFwuIiwgIi0iLCBmaWxlbmFtZSkKClNSQV9tZXRhZGF0YSRmaWxlbmFtZSA9IHBhc3RlMChmaWxlbmFtZSwgIl9SMV8wMDEuZmFzdHEuZ3oiKQpTUkFfbWV0YWRhdGEkZmlsZW5hbWUyID0gcGFzdGUwKGZpbGVuYW1lLCAiX1IyXzAwMS5mYXN0cS5neiIpCgppZiAoIWRpci5leGlzdHMoIkFuYWx5c2lzIFByb2R1Y3RzL1Byb2Nlc3NlZCBlRE5BL05DQkkiKSkgewogIGRpci5jcmVhdGUoIkFuYWx5c2lzIFByb2R1Y3RzL1Byb2Nlc3NlZCBlRE5BL05DQkkiLCByZWN1cnNpdmUgPSBUUlVFKQp9Cgp3cml0ZS5jc3YoCiAgTkNCSV9leHBvcnQsCiAgIkFuYWx5c2lzIFByb2R1Y3RzL1Byb2Nlc3NlZCBlRE5BL05DQkkvQmlvU2FtcGxlX0F0dHJpYnV0ZXMuY3N2IiwKICByb3cubmFtZXMgPSBGQUxTRSkKCndyaXRlLmNzdihTUkFfbWV0YWRhdGEsCiAgICAgICAgICAiQW5hbHlzaXMgUHJvZHVjdHMvUHJvY2Vzc2VkIGVETkEvTkNCSS9TUkFfbWV0YWRhdGEuY3N2IiwKICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCmBgYHtyIE1ha2luZyBHQklGIERhdGEgRnJhbWVzLCB3YXJuaW5nID0gRkFMU0V9CiMjI01ha2luZyBHQklGIERhdGEgRnJhbWVzIyMjCiMjQ3JlYXRlIGRhdGEgZnJhbWVzIGZvciBzdWJtaXNzaW9uIHRvIEdCSUYgdGhyb3VnaCB0aGUgYmV0YSBlRE5BIGRhdGEgY29udmVydGVyIChodHRwczovL2VkbmEtdG9vbC5nYmlmLXVhdC5vcmcvKQojRXhwb3J0IHZlcnNpb24gb2YgZGF0YSB3aXRoIGRlY29udGFtaW5hdGlvbiBhbmQgY29udHJvbHMgcmVtb3ZlZCBidXQgbm8gYWRkaXRpb25hbCBwcm9jZXNzaW5nCgojTWFrZSBkZWZhdWx0VmFsdWVzIGRhdGEgZnJhbWUgZm9yIHZhcmlhYmxlcyB0aGF0IGFyZSB0aGUgc2FtZSBmb3IgYWxsIHNhbXBsZXMKCmRlZmF1bHRWYWx1ZXMgPSBhcy5kYXRhLmZyYW1lKG1hdHJpeChuY29sID0gMiwgbnJvdyA9IDApKQpjb2xuYW1lcyhkZWZhdWx0VmFsdWVzKSA8LSBjKCd0ZXJtJywgJ3ZhbHVlJykKZGVmYXVsdFZhbHVlcyA9IGFzX3RpYmJsZShkZWZhdWx0VmFsdWVzKSAlPiUgbXV0YXRlKHRlcm0gPSBhcy5jaGFyYWN0ZXIodGVybSksIHZhbHVlID0gYXMuY2hhcmFjdGVyKHZhbHVlKSkKCmRlZmF1bHRWYWx1ZXMgPSBkZWZhdWx0VmFsdWVzICU+JQogIGFkZF9yb3codGVybSA9ICJlbnZfbWVkaXVtIiwgdmFsdWUgPSAiY29hc3RhbCBzZWEgd2F0ZXIgW0VOVk9fMDAwMDIxNTBdIikgJT4lCiAgYWRkX3Jvdyh0ZXJtID0gImVudl9icm9hZF9zY2FsZSIsIHZhbHVlID0gIm1hcmluZSBiaW9tZSBbRU5WTzowMDAwMDQ0N10iKSAlPiUKICBhZGRfcm93KHRlcm0gPSAiZW52X2xvY2FsX3NjYWxlIiwgdmFsdWUgPSAic2hvcmVsaW5lIFtFTlZPOjAwMDAwNDg2XXxpbnRlcnRpZGFsIHpvbmUgW0VOVk86MDAwMDAzMTZdIikgJT4lCiAgYWRkX3Jvdyh0ZXJtID0gInByb2plY3RfbmFtZSIsIHZhbHVlID0gIkVudmlyb25tZW50YWwgRE5BIG1ldGFiYXJjb2RpbmcgZGlmZmVyZW50aWF0ZXMgYmV0d2VlbiBtaWNyby1oYWJpdGF0cyB3aXRoaW4gdGhlIHJvY2t5IGludGVydGlkYWwiKSAlPiUKICBhZGRfcm93KHRlcm0gPSAidGFyZ2V0X2dlbmUiLCB2YWx1ZSA9ICJDT0kiKSAlPiUKICBhZGRfcm93KHRlcm0gPSAicGNyX3ByaW1lcl9mb3J3YXJkIiwgdmFsdWUgPSAiR0dXQUNXR0dXVEdBQUNXR1RXVEFZQ0NZQ0MiKSAlPiUKICBhZGRfcm93KHRlcm0gPSAicGNyX3ByaW1lcl9uYW1lX2ZvcndhcmQiLCB2YWx1ZSA9ICJtbENPSWludEYiKSAlPiUKICBhZGRfcm93KHRlcm0gPSAicGNyX3ByaW1lcl9yZXZlcnNlIiwgdmFsdWUgPSAiVEFJQUNZVENJR0dSVEdJQ0NSQUFSQUFZQ0EiKSAlPiUKICBhZGRfcm93KHRlcm0gPSAicGNyX3ByaW1lcl9uYW1lX3JldmVyc2UiLCB2YWx1ZSA9ICJqZ0hDTzIxOTgiKSAlPiUKICBhZGRfcm93KHRlcm0gPSAic29wIiwgdmFsdWUgPSAiaHR0cHM6Ly93d3cuYmlvcnhpdi5vcmcvY29udGVudC8xMC4xMTAxLzIwMjMuMDguMDMuNTUxNTQzdjEiKSAlPiUKICBhZGRfcm93KHRlcm0gPSAic2VxX21ldGgiLCB2YWx1ZSA9ICJJbGx1bWluYSBNaVNlcSIpICU+JQogIGFkZF9yb3codGVybSA9ICJzYW1wbGluZ1Byb3RvY29sIiwgdmFsdWUgPSAiaHR0cHM6Ly9keC5kb2kub3JnLzEwLjE3NTA0L3Byb3RvY29scy5pby5icDJsNjl5N2tscWUvdjIiKSAlPiUKICBhZGRfcm93KHRlcm0gPSAic2l6ZV9mcmFjIiwgdmFsdWUgPSAiMC4yMiBtaWNyb21ldGVyIikgJT4lCiAgYWRkX3Jvdyh0ZXJtID0gInNhbXBfdm9sX3dlX2RuYV9leHQiLCB2YWx1ZSA9ICIxMDAwIG1MIikgJT4lCiAgYWRkX3Jvdyh0ZXJtID0gInNhbXBfY29sbGVjX2RldmljZSIsIHZhbHVlID0gIkNvdmlkaWVuIHNpbmdsZS11c2UgZW50ZXJhbCBmZWVkaW5nIHBvdWNoIikgJT4lCiAgYWRkX3Jvdyh0ZXJtID0gInNhbXBfY29sbGVjX21ldGhvZCIsIHZhbHVlID0gIkNvdmlkaWVuIHNpbmdsZS11c2UgZW50ZXJhbCBmZWVkaW5nIHBvdWNoOiBodHRwczovL2R4LmRvaS5vcmcvMTAuMTc1MDQvcHJvdG9jb2xzLmlvLmJwMmw2OXk3a2xxZS92MiIpICU+JQogIGFkZF9yb3codGVybSA9ICJzYW1wX21hdF9wcm9jZXNzIiwgdmFsdWUgPSAiR3Jhdml0eSBmaWx0ZXJlZCB0aHJvdWdoIFN0ZXJpdmV4ICgwLjIyLcK1bSk6IGh0dHBzOi8vZHguZG9pLm9yZy8xMC4xNzUwNC9wcm90b2NvbHMuaW8uYnAybDY5eTdrbHFlL3YyIikgJT4lCiAgYWRkX3Jvdyh0ZXJtID0gImFubmVhbGluZ1RlbXAiLCB2YWx1ZSA9ICI2OS41IikgJT4lCiAgYWRkX3Jvdyh0ZXJtID0gImFubmVhbGluZ1RlbXBVbml0IiwgdmFsdWUgPSAiRGVncmVlcyBDZWxzaXVzIikgJT4lCiAgYWRkX3Jvdyh0ZXJtID0gImFtcGxpY29uU2l6ZSIsIHZhbHVlID0gIjMxMyIpICU+JQogIGFkZF9yb3codGVybSA9ICJhbXBsaWZpY2F0aW9uUmVhY3Rpb25Wb2x1bWUiLCB2YWx1ZSA9ICIyNSIpICU+JQogIGFkZF9yb3codGVybSA9ICJhbXBsaWNhdGlvblJlYWN0aW9uVm9sdW1lVW5pdCIsIHZhbHVlID0gIsK1bCIpICU+JQogIGFkZF9yb3codGVybSA9ICJudWNsX2FjaWRfZXh0IiwgdmFsdWUgPSAiaHR0cHM6Ly9keC5kb2kub3JnLzEwLjE3NTA0L3Byb3RvY29scy5pby5ld292MXF5eXlncjIvdjEiKSAlPiUKICBhZGRfcm93KHRlcm0gPSAibnVjbF9hY2lkX2FtcCIsIHZhbHVlID0gImh0dHBzOi8vZHguZG9pLm9yZy8xMC4xNzUwNC9wcm90b2NvbHMuaW8uZG02Z3Azd3BkdnpwL3YxIikgJT4lCiAgYWRkX3Jvdyh0ZXJtID0gImxpYl9sYXlvdXQiLCB2YWx1ZSA9ICJwYWlyZWQiKSAlPiUKICBhZGRfcm93KHRlcm0gPSAidmVyYmF0aW1EZXB0aCIsIHZhbHVlID0gIlN1cmZhY2UiKSAlPiUKICBhZGRfcm93KHRlcm0gPSAiYmFzaXNPZlJlY29yZCIsIHZhbHVlID0gIk1hdGVyaWFsIHNhbXBsZSIpICU+JQogIGFkZF9yb3codGVybSA9ICJpbnN0aXR1dGlvbklEIiwgdmFsdWUgPSAiaHR0cHM6Ly9yb3Iub3JnLzAwZjU0cDA1NCIpICU+JQogIGFkZF9yb3codGVybSA9ICJpbnN0aXR1dGlvbkNvZGUiLCB2YWx1ZSA9ICJTdGFuZm9yZCBVbml2ZXJzaXR5IikgJT4lCiAgYWRkX3Jvdyh0ZXJtID0gIm9yZ2FuaXNtUXVhbnRpdHlUeXBlIiwgdmFsdWUgPSAiRE5BIHNlcXVlbmNlIHJlYWRzIikgJT4lCiAgYWRkX3Jvdyh0ZXJtID0gIm90dV9kYiIsIHZhbHVlID0gIk1JRE9SSTIgcmVmZXJlbmNlIGRhdGFiYXNlLHYuIEdCMjUzICgyMCBEZWNlbWJlciAyMDIyKTogaHR0cHM6Ly93d3cucmVmZXJlbmNlLW1pZG9yaS5pbmZvL2Rvd25sb2FkLnBocCIpCgojTWFrZSB0YXhhLCBzYW1wbGVzLCBhbmQgT1RVIHRhYmxlIGZpbGVzCgpHQklGX2V4cG9ydCA9IGFtcF9ub2NvbnRyb2xzX0ZECgpHQklGX2V4cG9ydCRtZXRhZGF0YSA9IG1lcmdlKEdCSUZfZXhwb3J0JG1ldGFkYXRhLCBMb2NhdGlvbiwgYWxsID0gVCkKR0JJRl9leHBvcnQkdGF4JEtpbmdkb20gPSByZW1vdmVfTkNCSW51bXMoR0JJRl9leHBvcnQkdGF4JEtpbmdkb20pCkdCSUZfZXhwb3J0JHRheCRQaHlsdW0gPSByZW1vdmVfTkNCSW51bXMoR0JJRl9leHBvcnQkdGF4JFBoeWx1bSkKR0JJRl9leHBvcnQkdGF4JENsYXNzID0gcmVtb3ZlX05DQkludW1zKEdCSUZfZXhwb3J0JHRheCRDbGFzcykKR0JJRl9leHBvcnQkdGF4JE9yZGVyID0gcmVtb3ZlX05DQkludW1zKEdCSUZfZXhwb3J0JHRheCRPcmRlcikKR0JJRl9leHBvcnQkdGF4JEZhbWlseSA9IHJlbW92ZV9OQ0JJbnVtcyhHQklGX2V4cG9ydCR0YXgkRmFtaWx5KQpHQklGX2V4cG9ydCR0YXgkR2VudXMgPSByZW1vdmVfTkNCSW51bXMoR0JJRl9leHBvcnQkdGF4JEdlbnVzKQpHQklGX2V4cG9ydCR0YXgkU3BlY2llcyA9IHJlbW92ZV9OQ0JJbnVtcyhHQklGX2V4cG9ydCR0YXgkU3BlY2llcykKCiNBZGQgZGF0ZSArIHRpbWUKCkRhdGUgPSAiMjAyMi0wMS0yOCIKR0JJRl9leHBvcnQkbWV0YWRhdGEgPSBjYmluZChHQklGX2V4cG9ydCRtZXRhZGF0YSwgRGF0ZSkKCkdCSUZfZXhwb3J0JG1ldGFkYXRhJHZlcmJhdGltRXZlbnREYXRlIDwtCiAgbHVicmlkYXRlOjp5bWRfaG0ocGFzdGUoR0JJRl9leHBvcnQkbWV0YWRhdGEkRGF0ZSwgIlQiLCBHQklGX2V4cG9ydCRtZXRhZGF0YSRUaW1lKSwKICAgICAgICAgICAgICAgICAgICB0eiA9ICJVUy9QYWNpZmljIikKCkdCSUZfZXhwb3J0JG1ldGFkYXRhJGV2ZW50RGF0ZSA8LQogIHdpdGhfdHooR0JJRl9leHBvcnQkbWV0YWRhdGEkdmVyYmF0aW1FdmVudERhdGUsICJadWx1IikKClp1bHUgPC0gc3RhbXAoIjIwMjAtMDQtMDRUMTg6MDU6MDBaIikKR0JJRl9leHBvcnQkbWV0YWRhdGEkZXZlbnREYXRlID0gWnVsdShHQklGX2V4cG9ydCRtZXRhZGF0YSRldmVudERhdGUpCgpQU1QgPC0gc3RhbXAoIjIwMjAtMDQtMDRUMTg6MDU6MDBQU1QiKQpHQklGX2V4cG9ydCRtZXRhZGF0YSR2ZXJiYXRpbUV2ZW50RGF0ZSA9IFBTVChHQklGX2V4cG9ydCRtZXRhZGF0YSR2ZXJiYXRpbUV2ZW50RGF0ZSkKCm5hbWVzKEdCSUZfZXhwb3J0JG1ldGFkYXRhKVtuYW1lcyhHQklGX2V4cG9ydCRtZXRhZGF0YSkgPT0gJ1NhbXBsZSddIDwtCiAgJ2lkJwoKY29sX29yZGVyID0gYygKICAiaWQiLAogICJTYW1wbGVfTmFtZSIsCiAgIkxvY2F0aW9uIiwKICAiTGF0aXR1ZGUiLAogICJMb25naXR1ZGUiLAogICJDUlMiLAogICJldmVudERhdGUiLAogICJ2ZXJiYXRpbUV2ZW50RGF0ZSIsCiAgIlQiLAogICJTIgopCgpHQklGX2V4cG9ydCRtZXRhZGF0YSA9IEdCSUZfZXhwb3J0JG1ldGFkYXRhWywgY29sX29yZGVyXQoKI0lmIHlvdSBoYXZlIFNSQSBtZXRhZGF0YSByZWNvcmRzIGZyb20gc3VjY2Vzc2Z1bCBOQ0JJIHN1Ym1pc3Npb24sIHByb2Nlc3MgdGhlbSBoZXJlCgppZiAoZGlyLmV4aXN0cygiQW5hbHlzaXMgUHJvZHVjdHMvUHJvY2Vzc2VkIGVETkEvTkNCSS9OQ0JJIFVwbG9hZCBSZWNvcmQiKSkgewogIFNSQSA9IHJlYWQuZGVsaW0oCiAgICAiQW5hbHlzaXMgUHJvZHVjdHMvUHJvY2Vzc2VkIGVETkEvTkNCSS9OQ0JJIFVwbG9hZCBSZWNvcmQvbWV0YWRhdGEtMTQyODg3MjctcHJvY2Vzc2VkLW9rLnRzdiIsCiAgICBzZXAgPSAiXHQiCiAgKQogIFNSQSA9IFNSQVtjKCJhY2Nlc3Npb24iLCAiYmlvc2FtcGxlX2FjY2Vzc2lvbiIsICJzYW1wbGVfbmFtZSIpXQogIFNSQSRiaW9zYW1wbGVfYWNjZXNzaW9uID0gcGFzdGUwKCJodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L2Jpb3NhbXBsZS8/dGVybT0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNSQSRiaW9zYW1wbGVfYWNjZXNzaW9uKQogIFNSQSRhY2Nlc3Npb24gPSBwYXN0ZTAoImh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3Yvc3JhLz90ZXJtPSIsIFNSQSRhY2Nlc3Npb24pCiAgCiAgR0JJRl9leHBvcnQkbWV0YWRhdGEgPSBsZWZ0X2pvaW4oR0JJRl9leHBvcnQkbWV0YWRhdGEsIFNSQSwgYnkgPSBqb2luX2J5KGlkID09IHNhbXBsZV9uYW1lKSkKfQoKR0JJRl9leHBvcnQkbWV0YWRhdGEgPSBHQklGX2V4cG9ydCRtZXRhZGF0YSAlPiUgcmVuYW1lKAogIGFzc29jaWF0ZWRTZXF1ZW5jZXMgPSBhY2Nlc3Npb24sCiAgbWF0ZXJpYWxTYW1wbGVJRCA9IGJpb3NhbXBsZV9hY2Nlc3Npb24sCiAgdGVtcGVyYXR1cmUgPSBULAogIHNhbGluaXR5ID0gUwopCgojQWRkIHNlcXVlbmNlcyB0byBmaWxlCgpjdXJyZW50X3N1YmZvbGRlciA9ICJEYXRhL0FuYWNhcGEgUGlwZWxpbmUgT3V0cHV0L1RpZGUgUG9vbCA1MTg0IC0gMzEgSmFudWFyeSAyMDIzIgpmaWxlcGF0aCA9IHBhc3RlMChjdXJyZW50X3N1YmZvbGRlciwKICAgICAgICAgICAgICAgICAgIi9DTzEvQ08xX3RheG9ub215X3RhYmxlcy9DTzFfQVNWX3RheG9ub215X2RldGFpbGVkLnR4dCIpCgpBbmFjYXBhRGV0YWlsZWQgPSByZWFkLnRhYmxlKGZpbGVwYXRoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWMgPSAiLiIpCnNlcXVlbmNlcyA9IGFzLmRhdGEuZnJhbWUoQW5hY2FwYURldGFpbGVkWywgYygic2VxdWVuY2UiLCAic2VxdWVuY2VzRiIsICJzZXF1ZW5jZXNSIildKQpzZXF1ZW5jZXMkc2VxdWVuY2VfdW5tZXJnZWQgPSBwYXN0ZTAoCiAgIltVTk1FUkdFRCBTRVFVRU5DRSBDT01CSU5BVElPTl0gRjogIiwKICBzZXF1ZW5jZXMkc2VxdWVuY2VzRiwKICAiOyBSOiAiLAogIHNlcXVlbmNlcyRzZXF1ZW5jZXNSCikKCnNlcXVlbmNlcyA8LQogIHNlcXVlbmNlcyAlPiUgbXV0YXRlKHNlcXVlbmNlID0gaWZlbHNlKHNlcXVlbmNlID09ICIiLCBzZXF1ZW5jZV91bm1lcmdlZCwgc2VxdWVuY2UpKQoKcm93bmFtZXMoc2VxdWVuY2VzKSA9IEFuYWNhcGFEZXRhaWxlZCRDTzFfc2VxX251bWJlcgoKR0JJRl9leHBvcnQkdGF4ID0gbWVyZ2UoCiAgc2VxdWVuY2VzLAogIEdCSUZfZXhwb3J0JHRheCwKICBieSA9ICJyb3cubmFtZXMiLAogIGFsbC54ID0gRkFMU0UsCiAgYWxsLnkgPSBUUlVFLAogIHNvcnQgPSBGQUxTRQopCnJvd25hbWVzKEdCSUZfZXhwb3J0JHRheCkgPSBHQklGX2V4cG9ydCR0YXgkUm93Lm5hbWVzCgpjb2xfb3JkZXIgPSBjKCJzZXF1ZW5jZSIsCiAgICAgICAgICAgICAgIktpbmdkb20iLAogICAgICAgICAgICAgICJQaHlsdW0iLAogICAgICAgICAgICAgICJDbGFzcyIsCiAgICAgICAgICAgICAgIk9yZGVyIiwKICAgICAgICAgICAgICAiRmFtaWx5IiwKICAgICAgICAgICAgICAiR2VudXMiLAogICAgICAgICAgICAgICJTcGVjaWVzIikKCkdCSUZfZXhwb3J0JHRheCA9IEdCSUZfZXhwb3J0JHRheFssIGNvbF9vcmRlcl0KCmlmICghZGlyLmV4aXN0cygiQW5hbHlzaXMgUHJvZHVjdHMvUHJvY2Vzc2VkIGVETkEvR0JJRiIpKSB7CiAgZGlyLmNyZWF0ZSgiQW5hbHlzaXMgUHJvZHVjdHMvUHJvY2Vzc2VkIGVETkEvR0JJRiIsIHJlY3Vyc2l2ZSA9IFRSVUUpCn0KCndyaXRlLmNzdigKICBHQklGX2V4cG9ydCRhYnVuZCwKICAiQW5hbHlzaXMgUHJvZHVjdHMvUHJvY2Vzc2VkIGVETkEvR0JJRi9PVFV0YWJsZS5jc3YiLAogIHJvdy5uYW1lcyA9IFRSVUUpCgp3cml0ZS5jc3YoCiAgR0JJRl9leHBvcnQkdGF4LAogICJBbmFseXNpcyBQcm9kdWN0cy9Qcm9jZXNzZWQgZUROQS9HQklGL3RheGEuY3N2IiwKICByb3cubmFtZXMgPSBUUlVFKQoKd3JpdGUuY3N2KAogIEdCSUZfZXhwb3J0JG1ldGFkYXRhLAogICJBbmFseXNpcyBQcm9kdWN0cy9Qcm9jZXNzZWQgZUROQS9HQklGL3NhbXBsZXMuY3N2IiwKICByb3cubmFtZXMgPSBGQUxTRSkKCndyaXRlLmNzdigKICBkZWZhdWx0VmFsdWVzLAogICJBbmFseXNpcyBQcm9kdWN0cy9Qcm9jZXNzZWQgZUROQS9HQklGL2RlZmF1bHRWYWx1ZXMuY3N2IiwKICByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgoKVG8gZW5zdXJlIHRoZSBhY2N1cmFjeSBvZiB0YXhvbm9taWMgYXNzaWdubWVudHMsIHdlIGFuYWx5emVkIG9jY3VycmVuY2UgZGF0YSBmcm9tIHRoZSBHbG9iYWwgQmlvZGl2ZXJzaXR5IEluZm9ybWF0aW9uIEZhY2lsaXR5IHRvIGludmVzdGlnYXRlIHdoZXRoZXIgaWRlbnRpZmllZCBzcGVjaWVzIGhhZCBvY2N1cnJlbmNlIHJlY29yZHMgaW4gdGhlIENhbGlmb3JuaWEgQ3VycmVudCBTeXN0ZW0gYW5kIGtub3duIHJhbmdlcyB0aGF0IGVuY29tcGFzc2VkIFBpbGxhciBQb2ludCwgdXNpbmcgdGhlIGBzcG9jY2AgKHZlcnNpb24gYHIgcGFja2FnZVZlcnNpb24oInNwb2NjIilgIGBwYWNrYWdlVmVyc2lvbigic3BvY2MiKWApIChDaGFtYmVybGFpbiwgMjAyMSkgcGFja2FnZS4gQSBwaHlsb2dlbmV0aWMgdHJlZSBiYXNlZCBvbiB0YXhvbm9taWMgYXNzaWdubWVudHMgd2FzIGNyZWF0ZWQgdXNpbmcgdGhlIHRheGl6ZSAodmVyc2lvbiBgciBwYWNrYWdlVmVyc2lvbigidGF4aXplIilgIGBwYWNrYWdlVmVyc2lvbigidGF4aXplIilgKSAoQ2hhbWJlcmxhaW4gYW5kIFN6w7ZjcywgMjAxMykgYW5kIGdndHJlZUV4dHJhIGByIHBhY2thZ2VWZXJzaW9uKCJnZ3RyZWVFeHRyYSIpYCBgcGFja2FnZVZlcnNpb24oImdndHJlZUV4dHJhIilgIChjaXRhdGlvbikgcGFja2FnZXMuCgojIyMjIERhdGEgQW5hbHlzaXMKClRvIHVuZGVyc3RhbmQgd2hldGhlciBlRE5BIHNpZ25hbHMgY291bGQgYmUgZGlzdGluZ3Vpc2hlZCBieSBsb2NhdGlvbiwgd2UgZmlyc3QgYW5hbHl6ZWQgaW5kaXZpZHVhbC1sZXZlbCBkaWZmZXJlbmNlcyBiZXR3ZWVuIGxvY2F0aW9uczsgdGhhdCBpcywgd2hldGhlciBBU1ZzIG9yIGluZGl2aWR1YWwgdGF4YSAoYWdnbG9tZXJhdGVkIHNwZWNpZXMtbGV2ZWwgdGF4b25vbWljIGFzc2lnbm1lbnRzKSB3ZXJlIHVuaXF1ZSB0bywgb3IgYXNzb2NpYXRlZCB3aXRoLCBwYXJ0aWN1bGFyIGxvY2F0aW9ucy4gV2UgY2FsY3VsYXRlZCBhbmQgdmlzdWFsaXplZCB1bmlxdWUgQVNWcyBhbmQgdGF4YSB1c2luZyB0aGUgYGV1bGVycmAgKHZlcnNpb24gYHIgcGFja2FnZVZlcnNpb24oImV1bGVyciIpYCBgcGFja2FnZVZlcnNpb24oImV1bGVyciIpYCkgKExhcnNzb24sIDIwMjIpIHBhY2thZ2UuIEhvd2V2ZXIsIHdpdGggbWV0YWJhcmNvZGluZyBkYXRhIGluIHBhcnRpY3VsYXIsIHRheGEgb3IgQVNWcyB0aGF0IGFyZSB1bmlxdWUgdG8gYSBnaXZlbiBsb2NhdGlvbiBhcmUgbm90IG5lY2Vzc2FyaWx5IGVjb2xvZ2ljYWxseSBtZWFuaW5nZnVsOyB0aGV5IGNvdWxkIGluY2x1ZGUgcmFyZSB0YXhhIHByZXNlbnQgZWxzZXdoZXJlIGJ1dCBub3QgYW1wbGlmaWVkIGFuZCBleGNsdWRlIHRheGEgdGhhdCBhcmUgd2VsbCBjb3JyZWxhdGVkIHdpdGggcGFydGljdWxhciBsb2NhdGlvbnMgYnV0IHNvbWV0aW1lcyBkZXRlY3RlZCBhdCBvdGhlcnMuIFRodXMsIHdlIGFsc28gYW5hbHl6ZWQgQVNWcyBhbmQgdGF4YSB1c2luZyBhbiBpbmRpY2F0b3Igc3BlY2llcyBmcmFtZXdvcmsgKER1ZnLDqm5lIGFuZCBMZWdlbmRyZSwgMTk5NykuIEluIHRoaXMgZnJhbWV3b3JrLCB0aGUgbnVsbCBoeXBvdGhlc2lzIGlzIHRoYXQgdGhlIGZyZXF1ZW5jeSBvZiBhIHRheG9uJ3Mgb3IgQVNWJ3MgcHJlc2VuY2UgaW4gc2FtcGxlcyBmcm9tIGEgcGFydGljdWxhciBsb2NhdGlvbiBpcyBub3QgaGlnaGVyIHRoYXQgdGhlIGZyZXF1ZW5jeSBvZiB0aGF0IHRheG9uJ3Mgb3IgQVNWJ3MgcHJlc2VuY2UgaW4gc2FtcGxlcyBmcm9tIG90aGVyIGxvY2F0aW9ucy4gRm9yIGVhY2ggbG9jYXRpb24sIHdlIGlkZW50aWZpZWQgYWxsIHN0YXRpc3RpY2FsbHktc2lnbmlmaWNhbnQgaW5kaWNhdG9yIHRheGEgYW5kIEFTVnMgd2l0aCBpbmRpY2F0b3IgdmFsdWUgaW5kaWNlcyBhYm92ZSAwLjctLS10aGF0IGlzLCBpbmRpY2F0b3JzIHRoYXQgYXJlIHdlbGwtYXNzb2NpYXRlZCB3aXRoIGEgc2l0ZSBncm91cCBldmVuIGlmIHRoZXkgYXJlIGRldGVjdGVkIGluIHNhbXBsZXMgZnJvbSBvdGhlciBzaXRlcy0tLWJhc2VkIG9uIHByZXNlbmNlLWFic2VuY2UgZGF0YSBwZXIgc2FtcGxlIHVzaW5nIHRoZSBgaW5kaWNzcGVjaWVzYCBwYWNrYWdlICh2ZXJzaW9uIGByIHBhY2thZ2VWZXJzaW9uKCJpbmRpY3NwZWNpZXMiKWAgYHBhY2thZ2VWZXJzaW9uKCJpbmRpY3NwZWNpZXMiKWApIChDw6FjZXJlcyBhbmQgTGVnZW5kcmUsIDIwMDkpLgoKV2UgZm9sbG93ZWQgb3VyIGluZGl2aWR1YWwtbGV2ZWwgYW5hbHlzZXMgd2l0aCBhcHByb2FjaGVzIHRvIHRlc3Qgd2hldGhlciBjb21tdW5pdHkgY29tcG9zaXRpb24gdmFyaWVkIGJ5IGxvY2F0aW9uLiBXZSBjYWxjdWxhdGVkIGEgSmFjY2FyZCBkaXNzaW1pbGFyaXR5IG1hdHJpeCBhY3Jvc3MgYWxsIHNhbXBsZXMgdXNpbmcgYHZlZ2FuYCAodmVyc2lvbiBgciBwYWNrYWdlVmVyc2lvbigidmVnYW4iKWAgYHBhY2thZ2VWZXJzaW9uKCJ2ZWdhbiIpYCkgKE9rc2FuZW4gZXQgYWwuLCAyMDIyKS4gVGhlbiwgd2UgdGVzdGVkIGZvciBkaWZmZXJlbmNlcyBpbiBjb21tdW5pdHkgY29tcG9zaXRpb24gYW1vbmcgbG9jYXRpb25zIHVzaW5nIGEgcGVybXV0YXRpb25hbCBtdWx0aXZhcmlhdGUgYW5hbHlzaXMgb2YgdmFyaWFuY2UgKFBFUk1BTk9WQSkgd2l0aCB0aGUgbW9kZWwgZUROQSBQcmVzZW5jZSBcfiBMb2NhdGlvbiArIFRpbWUgKyBCaW9sb2dpY2FsIFJlcGxpY2F0ZXMgdXNpbmcgdGhlIGBhZG9uaXNgIGZ1bmN0aW9uIGluIGB2ZWdhbmAuIFdlIGNvbmZpcm1lZCB0aGF0IGxvY2F0aW9uYWwgZGlmZmVyZW5jZXMgZm91bmQgdmlhIFBFUk1BTk9WQSB3ZXJlIG5vdCBhIHJlc3VsdCBvZiBkaWZmZXJlbmNlcyBpbiBkaXNwZXJzaW9ucyBieSB0ZXN0aW5nIGZvciBob21vZ2VuZWl0eSBvZiBkaXNwZXJzaW9ucyB1c2luZyB0aGUgYGJldGFkaXNwZXJgIGZ1bmN0aW9uIGluIGB2ZWdhbmAuIFdlIGFsc28gdmlzdWFsaXplZCBKYWNjYXJkIGRpc3NpbWlsYXJpdHkgdXNpbmcgbm9uLW1ldHJpYyBtdWx0aWRpbWVuc2lvbmFsIHNjYWxpbmcgKE5NRFMpIHVzaW5nIHRoZSBgbWV0YU1EU2AgZnVuY3Rpb24gaW4gYHZlZ2FuYC4gV2UgY291cGxlZCB0aGVzZSBhbmFseXNlcyB3aXRoIGEgcGFydGl0aW9uaW5nIGFtb25nIG1lZG9pZHMgYWxnb3JpdGhtIChLYXVmbWFuIGFuZCBSb3Vzc2VldXcsIDE5OTApIGltcGxlbWVudGVkIHdpdGggdGhlIGBwYW1gIGZ1bmN0aW9uIGluIHRoZSBgY2x1c3RlcmAgcGFja2FnZSAodmVyc2lvbiBgciBwYWNrYWdlVmVyc2lvbigiY2x1c3RlciIpYCBgcGFja2FnZVZlcnNpb24oImNsdXN0ZXIiKWApIChNYWVjaGxlciBldCBhbC4sIDIwMjIpLiBSYXRoZXIgdGhhbiBhc3N1bWluZyBsb2NhdGlvbiBjbHVzdGVycyBhIHByaW9yaSwgd2UgdmFsaWRhdGVkIHRoZSBvcHRpbWFsIG51bWJlciBvZiBjbHVzdGVycyBmb3IgYSBnaXZlbiBkYXRhc2V0IGJ5IGZpbmRpbmcgdGhlIG51bWJlciBvZiBjbHVzdGVycyAoaykgdGhhdCBtYXhpbWl6ZWQgdGhlIGF2ZXJhZ2Ugc2lsaG91ZXR0ZSB3aWR0aCwgYSBtZWFzdXJlIG9mIGhvdyB3ZWxsLXN0cnVjdHVyZWQgdGhlIGNsdXN0ZXJzIGFyZS4gRmluYWxseSwgdG8gYmV0dGVyIHVuZGVyc3RhbmQgaG93IHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gbG9jYXRpb25zIHZhcmllZCBvdmVyIHRoZSB0aW1lIHNhbXBsZWQsIGZvciBlYWNoIHRpbWUgcG9pbnQsIHdlIGNhbGN1bGF0ZWQgdGhlIEphY2NhcmQgZGlzc2ltaWxhcml0eSBiZXR3ZWVuIGVhY2ggdW5pcXVlIGNvbWJpbmF0aW9uIG9mIHJlcGxpY2F0ZXMgd2l0aGluIGVhY2ggc2l0ZSwgYW5kIHRoZW4gdGhlIHBhaXJ3aXNlIEphY2NhcmQgZGlzc2ltaWxhcml0eSBiZXR3ZWVuIGVhY2ggdW5pcXVlIGNvbWJpbmF0aW9uIG9mIHNhbXBsZXMgYWNyb3NzIHRoZSB0aHJlZSBwYWlycyBvZiBzaXRlczogUzEtTiwgUzItTiwgYW5kIFMxLVMyLgoKVG8gZnVydGhlciBpbnZlc3RpZ2F0ZSB3aGV0aGVyIGRpZmZlcmVuY2VzIGluIGVETkEgZGV0ZWN0aW9ucyBjb3JyZXNwb25kZWQgd2l0aCB1bmRlcmx5aW5nIGVjb2xvZ2ljYWwgZ3JhZGllbnRzLCB3ZSBjb21wYXJlZCB0aGUgdW5pcXVlIGFuZCBpbmRpY2F0b3IgdGF4YSBpZGVudGlmaWVkIGF0IGVhY2ggc2l0ZSB0byB0aGVpciBlY29sb2dpY2FsIHpvbmF0aW9uIGluIGEgaGlnaGx5IHJlZ2FyZGVkIGZpZWxkIGd1aWRlIHRvIHRoZSBQYWNpZmljIGludGVydGlkYWwsIEJldHdlZW4gUGFjaWZpYyBUaWRlcyAoUmlja2V0dHMgZXQgYWwuLCAxOTg1KS4gVG8gYWNjb3VudCBmb3IgcG90ZW50aWFsIHZhcmlhdGlvbnMgaW4gdGF4b25vbWljIG5hbWVzIGJldHdlZW4gQmV0d2VlbiBQYWNpZmljIFRpZGVzIGFuZCB0aGUgTUlET1JJMiByZWZlcmVuY2UgZGF0YWJhc2UsIHdlIHVzZWQgdGhlIFdvcmxkIFJlZ2lzdGVyIG9mIE1hcmluZSBTcGVjaWVzIChXb1JNUykgdG8gaWRlbnRpZnkgYWxsIHN5bm9ueW1pemVkIG5hbWVzIGZvciBlYWNoIHVuaXF1ZSBhbmQgaW5kaWNhdG9yIHRheG9uIGlkZW50aWZpZWQgdXNpbmcgdGhlIGB0YXhpemVgICh2ZXJzaW9uIGByIHBhY2thZ2VWZXJzaW9uKCJ0YXhpemUiKWAgYHBhY2thZ2VWZXJzaW9uKCJ0YXhpemUiKWApIChTLiBBLiBDaGFtYmVybGFpbiAmIFN6w7ZjcywgMjAxMykgcGFja2FnZS4gVGhlbiwgd2Ugc2VhcmNoZWQgQmV0d2VlbiBQYWNpZmljIFRpZGVzIGZvciBhbGwgc3lub255bXMsIGJvdGggbWFudWFsbHkgdXNpbmcgdGhlIGluZGV4IGFuZCBpbiBSIGJ5IGV4dHJhY3RpbmcgdGhlIHRleHQgZnJvbSBhIFBERiBvZiBCZXR3ZWVuIFBhY2lmaWMgVGlkZXMgdXNpbmcgdGhlIGBwZGZ0b29sc2AgcGFja2FnZSAodmVyc2lvbiBgciBwYWNrYWdlVmVyc2lvbigicGRmdG9vbHMiKWAgYHBhY2thZ2VWZXJzaW9uKCJwZGZ0b29scyIpYCkgKE9vbXMsIDIwMjMpLiBXZSBjb21wYXJlZCB0aGUgcHJvcG9ydGlvbiBvZiAKWm9uZSAxICh1cHBlcm1vc3QgaG9yaXpvbiksIFpvbmUgMiAoaGlnaCBpbnRlcnRpZGFsKSwgYW5kIFpvbmUgMyAobWlkZGxlIGludGVydGlkYWwpIHNwZWNpZXMgaWRlbnRpZmllZCBhY3Jvc3MgZWFjaCBsb2NhdGlvbiB1c2luZyBhIGNoaS1zcXVhcmVkIHRlc3Qgd2l0aCBwLXZhbHVlcyBjb21wdXRlZCB2aWEgTW9udGUgQ2FybG8gc2ltdWxhdGlvbi4KCgojIyMgUmVzdWx0cwoKIyMjIyAzLjEgU2VxdWVuY2luZyBSZXN1bHRzICYgVGF4b25vbWljIERpdmVyc2l0eQoKYGBge3IsIEZ1bGwgT3V0cHV0IE1ldHJpY3N9CiMjI0Z1bGwgT3V0cHV0IE1ldHJpY3MjIyMKI0dlbmVyYXRlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBmdWxsIEFuYWNhcGEgUGlwZWxpbmUgcmVzdWx0cwoKI0dhdGhlciBpbmZvcm1hdGlvbiBhYm91dCBmdWxsIEFuYWNhcGEgUGlwZWxpbmUgcmVzdWx0cyBiZWZvcmUgYW55IHByb2Nlc3NpbmcKdG90YWxfQVNWcyA9IG5yb3coYW1wJGFidW5kKQp0b3RhbF9yZWFkcyA9IHN1bShhbXAkYWJ1bmQpCgpzYW1wbGVzID0gbGVuZ3RoKGFtcCRtZXRhZGF0YSRUeXBlW2FtcCRtZXRhZGF0YSRUeXBlID09ICJzYW1wbGUiXSkKY29udHJvbHMgPSBsZW5ndGgoYW1wJG1ldGFkYXRhJFR5cGVbYW1wJG1ldGFkYXRhJFR5cGUgPT0gImNvbnRyb2wiXSkKCiNDaGVjayBwb3NpdGl2ZSBQQ1IgY29udHJvbHMKYW1wX01DID0gYW1wX2ZpbHRlcl9zYW1wbGVzKGFtcCwgTG9jYXRpb24gJWluJSBjKCJNQyIpKQoKZGYgPSBtZXJnZShhbXBfTUMkYWJ1bmQsIGFtcF9NQyR0YXgsIGJ5ID0gJ3Jvdy5uYW1lcycpCmRmID0gZGZbLCBjKDI6MywgMTApXQpjb2xuYW1lcyhkZikgPSBjKCJNQzEiLCAiTUMyIiwgIlNwZWNpZXMiKQphZ2dfZGYgPC0KICBkZiAlPiUgZ3JvdXBfYnkoU3BlY2llcykgJT4lIHN1bW1hcmlzZShNQzFfUmVhZHMgPSBzdW0oTUMxKSwgTUMyX1JlYWRzID0gc3VtKE1DMikpICU+JSBhcnJhbmdlKGRlc2MoTUMxX1JlYWRzKSkKYWdnX2RmW2FnZ19kZiA9PSAiIl0gPSAiTm8gVGF4b25vbWljIEFzc2lnbm1lbnQiCmFnZ19kZiRTcGVjaWVzID0gcmVtb3ZlX05DQkludW1zKGFnZ19kZiRTcGVjaWVzKQphZ2dfZGYKCmFtcF9ub19NQyA9IGFtcF9maWx0ZXJfc2FtcGxlcyhhbXAsIShMb2NhdGlvbiAlaW4lIGMoIk1DIikpKQoKaWYgKGxlbmd0aChpbnRlcnNlY3Qocm93bmFtZXMoYW1wX01DJGFidW5kKSwgcm93bmFtZXMoYW1wX25vX01DJGFidW5kKSkpID09IDApIHsKICBNQ19vdmVybGFwID0gIm5vIEFTVnMgcHJlc2VudCBpbiB0aGUgcG9zaXRpdmUgUENSIGNvbnRyb2xzIG9jY3VycmVkIGluIGFueSBvdGhlciBzYW1wbGVzLCBwcm92aWRpbmcgbm8gZXZpZGVuY2Ugb2YgaW5kZXggaG9wcGluZyIKfSBlbHNlIHsKICBNQ19vdmVybGFwID0gInNvbWUgQVNWcyBwcmVzZW50IGluIHRoZSBwb3NpdGl2ZSBQQ1IgY29udHJvbHMgb2NjdXJyZWQgaW4gb3RoZXIgc2FtcGxlcywgcHJvdmlkaW5nIGV2aWRlbmNlIG9mIGluZGV4IGhvcHBpbmcgKENIRUNLIFRISVMpIgp9CgojQ2hlY2sgaW50ZXJzZWN0aW9uIGJldHdlZW4gc2FtcGxlcyBhbmQgY29udHJvbHMKaW50ZXJzZWN0ID0gaW50ZXJzZWN0KHJvd25hbWVzKGFtcF9jb250cm9scyRhYnVuZCksCiAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhhbXBfbm9jb250cm9scyRhYnVuZCkpCm92ZXJsYXAgPSBsZW5ndGgoaW50ZXJzZWN0KQoKb3ZlcmxhcF90YWJsZSA9IGRhdGEuZnJhbWUoQVNWID0gaW50ZXJzZWN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAiVGF4b25vbWljIEFzc2lnbm1lbnQiID0gYW1wX25vY29udHJvbHMkdGF4W2FtcF9ub2NvbnRyb2xzJHRheCRPVFUgJWluJSBpbnRlcnNlY3QsIF0kU3BlY2llcykKb3ZlcmxhcF90YWJsZSRUYXhvbm9taWMuQXNzaWdubWVudCA9IHJlbW92ZV9OQ0JJbnVtcyhvdmVybGFwX3RhYmxlJFRheG9ub21pYy5Bc3NpZ25tZW50KQpvdmVybGFwX3RhYmxlCmBgYAoKVXNpbmcgdGhlIEFuYWNhcGEgVG9vbGtpdCwgd2UgaWRlbnRpZmllZCBgciB0b3RhbF9BU1ZzYCAoYHRvdGFsX0FTVnNgKSBBU1ZzIGZyb20gYHIgdG90YWxfcmVhZHNgKGB0b3RhbF9yZWFkc2ApIHJlYWRzIGFjcm9zcyBgciBzYW1wbGVzYCAoYHNhbXBsZXNgKSBzYW1wbGVzIGFuZCBgciBjb250cm9sc2AgKGBjb250cm9sc2ApIGNvbnRyb2xzIChwb3NpdGl2ZSBQQ1IgY29udHJvbHMsIG5lZ2F0aXZlIGZpZWxkIGNvbnRyb2xzLCBuZWdhdGl2ZSBleHRyYWN0aW9uIGNvbnRyb2xzLCBhbmQgbm8tdGVtcGxhdGUgbmVnYXRpdmUgUENSIGNvbnRyb2xzKS4gQWxsIGV4cGVjdGVkIHRheGEgYW1wbGlmaWVkIGluIGVhY2ggcG9zaXRpdmUgUENSIGNvbnRyb2wsIGFuZCBgciBNQ19vdmVybGFwYCAoYE1DX292ZXJsYXBgKS4gQmVmb3JlIGFwcGxpY2F0aW9uIG9mIGFueSBkZWNvbnRhbWluYXRpb24gc3RlcHMsIG9ubHkgYHIgb3ZlcmxhcGAgKGBvdmVybGFwYCkgQVNWcyB3ZXJlIHNoYXJlZCBiZXR3ZWVuIHRoZSBzYW1wbGVzIGFuZCBuZWdhdGl2ZSBmaWVsZCwgZXh0cmFjdGlvbiwgYW5kIFBDUiBjb250cm9scy4KCmBgYHtyLCBDb3JlIERhdGEgU2V0c30KIyMjQ29yZSBEYXRhIFNldHMjIyMKI0VzdGFibGlzaCBwcm9jZXNzZWQgZGF0YSBzZXQgdXNlZCB0aHJvdWdob3V0IGFuYWx5c2VzCgpkYXRhX2FtcCA9IGFtcF9ub2NvbnRyb2xzX05TX0ZEX1IKCmRhdGFfcGh5c2VxID0gYW1wX3RvX3BoeWxvc2VxKGRhdGFfYW1wLCBOVUxMLCBOVUxMLCBOVUxMKQoKZGF0YV9hbXBfdGF4YSA9IGRhdGFfYW1wCmRhdGFfYW1wX3RheGEkYWJ1bmQgPSBhZ2dyZWdhdGVfYWJ1bmQoZGF0YV9hbXAkYWJ1bmQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YV9hbXAkdGF4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRheF9hZ2dyZWdhdGUgPSAiU3BlY2llcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybWF0ID0gImFidW5kIikKCmlmICghZGlyLmV4aXN0cygiQW5hbHlzaXMgUHJvZHVjdHMvUHJvY2Vzc2VkIGVETkEvTWFudXNjcmlwdCBBbmFseXNpcyIpKSB7CiAgZGlyLmNyZWF0ZSgiQW5hbHlzaXMgUHJvZHVjdHMvUHJvY2Vzc2VkIGVETkEvTWFudXNjcmlwdCBBbmFseXNpcyIsCiAgICAgICAgICAgICByZWN1cnNpdmUgPSBUUlVFKQp9Cgp3cml0ZS5jc3YoCiAgZGF0YV9hbXAkYWJ1bmQsCiAgIkFuYWx5c2lzIFByb2R1Y3RzL1Byb2Nlc3NlZCBlRE5BL01hbnVzY3JpcHQgQW5hbHlzaXMvQVNWVGFibGUuY3N2IiwKICByb3cubmFtZXMgPSBUUlVFCikKCndyaXRlLmNzdigKICBkYXRhX2FtcCR0YXgsCiAgIkFuYWx5c2lzIFByb2R1Y3RzL1Byb2Nlc3NlZCBlRE5BL01hbnVzY3JpcHQgQW5hbHlzaXMvVGF4VGFibGUuY3N2IiwKICByb3cubmFtZXMgPSBUUlVFCikKCndyaXRlLmNzdigKICBkYXRhX2FtcCRtZXRhZGF0YSwKICAiQW5hbHlzaXMgUHJvZHVjdHMvUHJvY2Vzc2VkIGVETkEvTWFudXNjcmlwdCBBbmFseXNpcy9TYW1wbGVEYXRhLmNzdiIsCiAgcm93Lm5hbWVzID0gRkFMU0UKKQoKYGBgCgpgYGB7ciwgRmlndXJlIDMgLS1Db250aW51ZWQsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCByZXN1bHRzID0gRkFMU0UsIGZpZy53aWR0aD0gMTY5LCBmaWcuaGVpZ2h0ID0gMjAwfQojIyNGaWd1cmUgMy0tQ29udGludWVkIyMjCiNGaW5pc2ggdGhlIGJvdHRvbSBwb3J0aW9uIG9mIEZpZ3VyZSAzIG5vdyB0aGF0IGRhdGEgaGFzIGJlZW4gbG9hZGVkCgpkYXRhX2ZvcmNoYXJ0ID0gYW1wJG1ldGFkYXRhWyFpcy5uYShhbXAkbWV0YWRhdGEkVGltZSksIF0KCmRhdGFfZm9yY2hhcnQgPSBkYXRhX2ZvcmNoYXJ0ICU+JSAKICBncm91cF9ieShTaXRlQnlUaW1lKSAlPiUgCiAgbXV0YXRlKGNoYXJ0X251bSA9IGNlaWxpbmcocm93X251bWJlcigpLzMpKQoKZmFjZXQubGFicyA9ICBjKCJUaWRlIFBvb2wgMVxuIChTMSkiLAogICAgICAgICAgICAgICAgIlRpZGUgUG9vbCAyXG4gKFMyKSIsCiAgICAgICAgICAgICAgICAiTmVhcnNob3JlXG4gKE4pIiwKICAgICAgICAgICAgICAgICJGaWVsZCBCbGFuayIpCm5hbWVzKGZhY2V0LmxhYnMpID0gYygiUzEiLCAiUzIiLCAiTiIsICJGQiIpCgpkYXRhX2ZvcmNoYXJ0JExvY2F0aW9uID0gZmFjdG9yKGRhdGFfZm9yY2hhcnQkTG9jYXRpb24sIGxldmVscyA9IGMoIlMxIiwgIlMyIiwgIk4iLCAiRkIiKSkKZGF0YV9mb3JjaGFydCRjaGFydF9udW0gPSBmYWN0b3IoZGF0YV9mb3JjaGFydCRjaGFydF9udW0sIGxldmVscyA9IGMoIjMiLCAiMiIsICIxIikpCgpzYW1wbGVfc2NoZW1hID0gZ2dwbG90KGRhdGEgPSBkYXRhX2ZvcmNoYXJ0LAogICAgICAgICAgICAgICAgICAgICAgIGFlcygKICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBUaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGNoYXJ0X251bSwKICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gTG9jYXRpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IFRpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gYWZ0ZXJfc2NhbGUoYWxwaGEoY29sb3VyLCAwLjA1KSkKICAgICAgICAgICAgICAgICAgICAgICApKSArCiAgZ2VvbV9iZWVzd2FybShjZXggPSAyLCBzaXplID0gMykgKwogIGdlb21fYm94KAogICAgYWVzKAogICAgICB4bWluID0gYWZ0ZXJfc3RhdCh4KSAtIDAuNDUsCiAgICAgIHhtYXggPSBhZnRlcl9zdGF0KHgpICsgMC40NSwKICAgICAgeW1pbiA9IGFmdGVyX3N0YXQoeSkgLSAwLjQ1LAogICAgICB5bWF4ID0gYWZ0ZXJfc3RhdCh5KSArIDAuNDUKICAgICksCiAgICByYWRpdXMgPSB1bml0KDUsICJwdCIpCiAgKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMTUsIDE3LCAxNiwgMTgpKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKGRpcmVjdGlvbiA9IC0xLAogICAgICAgICAgICAgICAgICAgICAgICBiZWdpbiA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgIGVuZCA9IC45NykgKwogIGZhY2V0X2dyaWQoCiAgICBMb2NhdGlvbiB+IC4sCiAgICBzY2FsZXMgPSAiZnJlZV95IiwKICAgIHNwYWNlID0gImZyZWVfeSIsCiAgICBzd2l0Y2ggPSAieSIsCiAgICBsYWJlbGxlciA9IGxhYmVsbGVyKExvY2F0aW9uID0gZmFjZXQubGFicykKICApICsKICB0aGVtZV92b2lkKGJhc2Vfc2l6ZSA9IDEyKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICBzdHJpcC50ZXh0LnkubGVmdCA9IGVsZW1lbnRfdGV4dCgKICAgICAgYW5nbGUgPSAwLAogICAgICBoanVzdCA9IDEsCiAgICAgIHZqdXN0ID0gLjkKICAgICksCiAgICBwbG90Lm1hcmdpbiA9IGdncGxvdDI6Om1hcmdpbigwLCAwLCAwLCAwLCAicHQiKQogICkgICsKICB0aGVtZShheGlzLnRpY2tzLnggID0gZWxlbWVudF9saW5lKGxpbmV3aWR0aCA9IC41KSkgKwogIHRoZW1lKGF4aXMudGlja3MubGVuZ3RoLnggID0gdW5pdCgwLjE1LCAiY20iKSkgKwogIHNjYWxlX3hfZGlzY3JldGUocG9zaXRpb24gPSAidG9wIikKCgpjb21iaW5lZCA9IChwbG90X3NwYWNlcigpICsgcF9wYXRjaCArIHBsb3Rfc3BhY2VyKCkgKyBwbG90X2xheW91dCh3aWR0aHMgPSBjKDMsIDUwLCAxLjIpKSkgLwogIChwbG90X3NwYWNlcigpKSAvIChwbG90X3NwYWNlcigpICsgc2FtcGxlX3NjaGVtYSArIHBsb3RfbGF5b3V0KHdpZHRocyA9IGMoMSwgNTApKSkgKyBwbG90X2xheW91dChoZWlnaHRzID0gYyg0LC0uMDUsIDUpKSAmCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBnZ3Bsb3QyOjptYXJnaW4oMCwgMCwgMCwgMCwgInB0IikpCgpwYXRoID0gIkZpZ3VyZXMvRmlndXJlM19mdWxsLiIKc2F2ZV9wZGZfcG5nKAogIHBsb3QgPSBjb21iaW5lZCwKICBwYXRoID0gcGF0aCwKICB3ID0gMTY5LAogIGggPSAxNjksCiAgdSA9ICJtbSIsCiAgYmcgPSAidHJhbnNwYXJlbnQiLAogIGRwaSA9IDYwMAopCmBgYAoKPGNlbnRlcj4KCiFbKkZpZ3VyZSAzOiBHcmFwaCBvZiB0aWRlIHByZWRpY3Rpb25zIGR1cmluZyBmaWVsZCBzYW1wbGluZyBvbiAyOCBKYW51YXJ5IDIwMjIsIHdpdGggaWNvbnMgdG8gaW5kaWNhdGUgdGhlIHNhbXBsaW5nIHNjaGVtZSpdKGByIHBhc3RlMChwYXRoLCAicG5nIilgKQoKPC9jZW50ZXI+CgpgYGB7ciwgUHJvY2Vzc2VkIE91dHB1dCBNZXRyaWNzfQojIyNQcm9jZXNzZWQgT3V0cHV0IE1ldHJpY3MjIyMKI0dhdGhlciBpbmZvcm1hdGlvbiBhYm91dCBwcm9jZXNzZWQgQW5hY2FwYSBUb29sa2l0Cgpwcm9jZXNzZWRfQVNWcyA9IG5yb3coZGF0YV9hbXAkYWJ1bmQpCnByb2Nlc3NlZF9yZWFkcyA9IHN1bShkYXRhX2FtcCRhYnVuZCkKCiNDcmVhdGUgYSBwaHlsb3NlcSBvYmplY3Qgd2hlcmUgYWxsIHNhbXBsZXMgYXJlIGNvbWJpbmVkIGludG8gb25lCnRvdGFsID0gYXMuZGF0YS5mcmFtZShyb3dTdW1zKGRhdGFfYW1wJGFidW5kKSkKcGh5c2VxX3N1bW1lZCA9IGFtcF90b19waHlsb3NlcShOVUxMLCB0b3RhbCwgZGF0YV9hbXAkdGF4WywgMTo3XSwgTlVMTCkKCiNTdW1tYXJpemUgdGhlIG51bWJlciBvZiB1bmFzc2lnbmVkIEFTVnMKa2luZ2RvbSA9IGFzLmRhdGEuZnJhbWUodGF4X3RhYmxlKHBoeXNlcV9zdW1tZWQpWywgMV0pCnVuYXNzaWduZWRfQVNWcyA9IGtpbmdkb20gJT4lIAogIGdyb3VwX2J5KEtpbmdkb20pICU+JSAKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIAogIG11dGF0ZSAoZnJlcSA9IG4gLyBzdW0obikpCgojU3VtbWFyaXplIG51bWJlciBvZiB1bmlxdWUgdGF4YSBhdCBlYWNoIHRheG9ub21pYyBsZXZlbAp1bmlxdWUgPSBhcHBseSh0YXhfdGFibGUocGh5c2VxX3N1bW1lZCksIDIsIGZ1bmN0aW9uKHgpCiAgbGVuZ3RoKHVuaXF1ZSh4W3ggIT0gIiJdKSkpCmBgYAoKYGBge3IsIEdCSUYgU2V0LVVwLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KIyMjR0JJRiBTZXQtVXAjIyMKI0NyZWF0ZSBmdW5jdGlvbnMgYW5kIGRhdGFzZXRzIG5lZWRlZCBmb3IgR0JJRiBhbmFseXNpcwoKI0NyZWF0ZSBsaXN0IG9mIGlkZW50aWZpZWQgc3BlY2llcwpzcGVjaWVzX2xpc3QgPSB1bmlxdWUoZGF0YV9hbXAkdGF4JFNwZWNpZXMpCnNwZWNpZXNfbGlzdCA9IHJlbW92ZV9OQ0JJbnVtcyhzcGVjaWVzX2xpc3QpCnNwZWNpZXNfbGlzdCA9IHNwZWNpZXNfbGlzdFtzcGVjaWVzX2xpc3QgIT0gIiJdCnNwZWNpZXNfbGlzdCA9IHN1YigiXyIsICItIiwgc3BlY2llc19saXN0KSAjdG8gYWRkcmVzcyBQc2V1ZG9fbml0emNoaWEgZXJyb3IKCiNTdGFuZGFyZGl6ZSBzcGVjaWVzIG5hbWVzIGFnYWluc3QgR0JJRiBiYWNrYm9uZQpzcGVjaWVzX0dCSUYgPSBuYW1lX2JhY2tib25lX2NoZWNrbGlzdChzcGVjaWVzX2xpc3QpCnNwZWNpZXNfc3RhbmRhcmRpemVkID0gc3BlY2llc19HQklGJHNwZWNpZXNbIWlzLm5hKHNwZWNpZXNfR0JJRiRzcGVjaWVzKV0Kc3BlY2llc19ib3RoID0gc3BlY2llc19HQklGW2MoInNwZWNpZXMiLCAidmVyYmF0aW1fbmFtZSIpXQoKIyNDb3JlIEdCSUYgY2hlY2tpbmcgZnVuY3Rpb24KZGlzdHJpYnV0aW9uX2NoZWNrIDwtCiAgZnVuY3Rpb24oc21hbGxfYm91bmQsCiAgICAgICAgICAgYmlnX2JvdW5kLAogICAgICAgICAgIHNwZWNpZXMsCiAgICAgICAgICAgbWluX3JlY29yZHMsCiAgICAgICAgICAgZWZmaWNpZW5jeSkgewogICAgIyNGdW5jdGlvbiB0aGF0IGNoZWNrcyBHQklGIGdpdmVuIGEgcGFydGljdWxhciBnZW9ncmFwaGljIHJlZ2lvbgogICAgYm91bmRhcnlfZnVuY3Rpb24gPC0gZnVuY3Rpb24oc3BlY2llcywgYm91bmRzKSB7CiAgICAgIG5vX2RhdGEgPSBjKCkKICAgICAgY29uZmlybWVkID0gYygpCiAgICAgIGZvciAoaSBpbiBzcGVjaWVzKSB7CiAgICAgICAgcHJpbnQoaSkKICAgICAgICBvY2MgPSBvY2MoCiAgICAgICAgICBxdWVyeSA9IGksCiAgICAgICAgICBnZW9tZXRyeSA9IGJvdW5kcywKICAgICAgICAgIGZyb20gPSAnZ2JpZicsCiAgICAgICAgICBsaW1pdCA9IG1pbl9yZWNvcmRzLAogICAgICAgICAgaGFzX2Nvb3JkcyA9IFRSVUUsCiAgICAgICAgICBnYmlmb3B0cyA9IGxpc3QoaGFzR2Vvc3BhdGlhbElzc3VlID0gRkFMU0UpCiAgICAgICAgKQogICAgICAgIG9jYy5kZiA9IG9jYzJkZihvY2MpCiAgICAgICAgaWYgKG5yb3cob2NjLmRmKSA+PSBtaW5fcmVjb3JkcykgewogICAgICAgICAgY29uZmlybWVkID0gYXBwZW5kKGNvbmZpcm1lZCwgaSkKICAgICAgICB9IGVsc2UgewogICAgICAgICAgbm9fZGF0YSA9IGFwcGVuZChub19kYXRhLCBpKQogICAgICAgIH0KICAgICAgfQogICAgICByZXR1cm4obGlzdChub19kYXRhID0gbm9fZGF0YSwgY29uZmlybWVkID0gY29uZmlybWVkKSkKICAgIH0KICAgIAojI0Z1bmN0aW9uIHRoYXQgY2hlY2tzIEdCSUYgdG8gY29uZmlybSB3aGV0aGVyIGEgcGFydGljdWxhciBsb2NhdGlvbiBpcyB3aXRoaW4gdGhlIHJhbmdlIG9mIG9ic2VydmF0aW9ucwogICAgcmFuZ2VfZnVuY3Rpb24gPC0gZnVuY3Rpb24oc3BlY2llcykgewogICAgICBDQy5jb25maXJtZWQgPSBjKCkKICAgICAgQ0Mubm90X2NvbmZpcm1lZCA9IGMoKQogICAgICBDQy5ub19kYXRhID0gYygpCiAgICAgIGxpbWl0cyA9IGMoMTAsIDEwMCwgMTAwMCwgMTAwMDApCiAgICAgIAogICAgICBmb3IgKGkgaW4gc3BlY2llcykgewogICAgICAgIHRyYWNrID0gMAogICAgICAgIGZvciAobCBpbiBsaW1pdHMpIHsKICAgICAgICAgIHByaW50KGkpCiAgICAgICAgICBwcmludCAobCkKICAgICAgICAgIG9jYyA9IG9jYygKICAgICAgICAgICAgaSwKICAgICAgICAgICAgZnJvbSA9ICdnYmlmJywKICAgICAgICAgICAgbGltaXQgPSBsLAogICAgICAgICAgICBoYXNfY29vcmRzID0gVFJVRSwKICAgICAgICAgICAgZ2JpZm9wdHMgPSBsaXN0KGhhc0dlb3NwYXRpYWxJc3N1ZSA9IEZBTFNFKQogICAgICAgICAgKQogICAgICAgICAgb2NjLmRmID0gb2NjMmRmKG9jYykKICAgICAgICAgIGlmIChucm93KG9jYy5kZikgPCBtaW5fcmVjb3JkcykgewogICAgICAgICAgICBDQy5ub19kYXRhID0gYXBwZW5kKENDLm5vX2RhdGEsIGkpCiAgICAgICAgICAgIHByaW50KCJubyBkYXRhIikKICAgICAgICAgICAgdHJhY2sgPSAxCiAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICB9CiAgICAgICAgICBiYl9vY2MgPSBzcDo6YmJveChjYmluZChvY2MuZGYkbG9uZ2l0dWRlLCBvY2MuZGYkbGF0aXR1ZGUpKQogICAgICAgICAgaWYgKGJiX29jY1sneCcsICdtaW4nXSA8IHNtYWxsX2JvdW5kWzFdICYKICAgICAgICAgICAgICBiYl9vY2NbJ3gnLCAnbWF4J10gPiBzbWFsbF9ib3VuZFsxXSAmCiAgICAgICAgICAgICAgYmJfb2NjWyd5JywgJ21pbiddIDwgc21hbGxfYm91bmRbNF0gJgogICAgICAgICAgICAgIGJiX29jY1sneScsICdtYXgnXSA+IHNtYWxsX2JvdW5kWzRdKSB7CiAgICAgICAgICAgIENDLmNvbmZpcm1lZCA9IGFwcGVuZChDQy5jb25maXJtZWQsIGkpCiAgICAgICAgICAgIHByaW50KCJjb25maXJtZWQiKQogICAgICAgICAgICB0cmFjayA9IDEKICAgICAgICAgICAgYnJlYWsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChucm93KG9jYy5kZikgPCBsKSB7CiAgICAgICAgICAgIENDLm5vdF9jb25maXJtZWQgPSBhcHBlbmQoQ0Mubm90X2NvbmZpcm1lZCwgaSkKICAgICAgICAgICAgcHJpbnQoIm5vdCBjb25maXJtZWQiKQogICAgICAgICAgICB0cmFjayA9IDEKICAgICAgICAgICAgYnJlYWsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKHRyYWNrID09IDApIHsKICAgICAgICAgIENDLm5vdF9jb25maXJtZWQgPSBhcHBlbmQoQ0Mubm90X2NvbmZpcm1lZCwgaSkKICAgICAgICAgIHByaW50KCJub3QgY29uZmlybWVkIikKICAgICAgICB9CiAgICAgIH0KICAgICAgcmV0dXJuKAogICAgICAgIGxpc3QoCiAgICAgICAgICBub19kYXRhID0gQ0Mubm9fZGF0YSwKICAgICAgICAgIG5vdF9jb25maXJtZWQgPSBDQy5ub3RfY29uZmlybWVkLAogICAgICAgICAgY29uZmlybWVkID0gQ0MuY29uZmlybWVkCiAgICAgICAgKQogICAgICApCiAgICB9CiAgICAKICAgIAogICAgI0FjdHVhbCBTdGVwcwogICAgUFAgPSBib3VuZGFyeV9mdW5jdGlvbihzcGVjaWVzLCBzbWFsbF9ib3VuZCkKICAgIAogICAgaWYgKGVmZmljaWVuY3kgPT0gVFJVRSkgewogICAgICBDQyA9IGJvdW5kYXJ5X2Z1bmN0aW9uKFBQW1sibm9fZGF0YSJdXSwgYmlnX2JvdW5kKQogICAgfSBlbHNlIHsKICAgICAgQ0MgPSBib3VuZGFyeV9mdW5jdGlvbihzcGVjaWVzLCBiaWdfYm91bmQpCiAgICB9CiAgICAKICAgIGlmIChlZmZpY2llbmN5ID09IFRSVUUpIHsKICAgICAgcmFuZ2VfY29uZmlybWVkID0gcmFuZ2VfZnVuY3Rpb24oQ0NbWyJjb25maXJtZWQiXV0pCiAgICAgIHJhbmdlX3VuY29uZmlybWVkID0gcmFuZ2VfZnVuY3Rpb24oQ0NbWyJub3RfY29uZmlybWVkIl1dKQogICAgICByZXR1cm4obGlzdChQUCwgQ0MsIHJhbmdlX2NvbmZpcm1lZCwgcmFuZ2VfdW5jb25maXJtZWQpKQogICAgfSBlbHNlIHsKICAgICAgcmFuZ2UgPSByYW5nZV9mdW5jdGlvbihzcGVjaWVzKQogICAgICByZXR1cm4obGlzdChQUCwgQ0MsIHJhbmdlKSkKICAgIH0KICB9CgojR2V0IHRoZSBDYWxpZm9ybmlhIEN1cnJlbnQgU3lzdGVtIHNoYXBlCgpDQ19zaGFwZSA9IG1yX2ZlYXR1cmVzX2dldCh0eXBlID0gIk1hcmluZVJlZ2lvbnM6bG1lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZUlEID0gImxtZS4xMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdCA9ICJqc29uIikKCiNjaGVjayB0aGF0IGl0J3MgdGhlIHJpZ2h0IHBvbHlnb24KY2xhc3MoQ0Nfc2hhcGUpIDwtICJtcl9nZW9qc29uIgpDQ19zaGFwZSA9IG1yX2FzX3drdChDQ19zaGFwZSkKcG50IDwtIHN0X2FzX3NmYyhDQ19zaGFwZSwgY3JzID0gNDMyNikKbWFwdmlldyhwbnQpCgojU2ltcGxpZnkgdGhlIHBvbHlnb24gZm9yIHVzZSB3aXRoIEdCSUYKQ0Nfc2hhcGVfc3AgPSBzdF90cmFuc2Zvcm0ocG50LCBjcnMgPSAnK3Byb2o9YWVxZCArbGF0XzA9NTMuNiArbG9uXzA9MTIuNycpCm1hcHZpZXcoQ0Nfc2hhcGVfc3ApCkNDX3NoYXBlX3NwID0gc3Rfc2ltcGxpZnkoQ0Nfc2hhcGVfc3AsCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlc2VydmVUb3BvbG9neSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgIGRUb2xlcmFuY2UgPSAyMDAwMCkKQ0Nfc2hhcGVfc3AgPSBzdF90cmFuc2Zvcm0oQ0Nfc2hhcGVfc3AsIGNycyA9IDQzMjYpCm1hcHZpZXcoQ0Nfc2hhcGVfc3ApCgojUmV2ZXJzZSBvcmRlciBmb3IgR0JJRgpDQ19zaGFwZV9zcFtbMV1dW1sxXV1bLDFdID0gcmV2KENDX3NoYXBlX3NwW1sxXV1bWzFdXVssMV0pCkNDX3NoYXBlX3NwW1sxXV1bWzFdXVssMl0gPSByZXYoQ0Nfc2hhcGVfc3BbWzFdXVtbMV1dWywyXSkKCmBgYAoKYGBge3IsIEdCSUYgUnVuLCBjYWNoZT1UUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgcmVzdWx0cyA9ICdoaWRlJ30KIyMjR0JJRiBSdW4jIyMKI1J1biBmdW5jdGlvbiB0aGF0IGRvZXMgR0JJRiBhbmFseXNpcyAodGhpcyB0YWtlcyBhIGxvbmcgdGltZTsgcmVjb21tZW5kIHJ1bm5pbmcgd2l0aCBqb2I6OmpvYigpIHdoZW4gd29ya2luZyBpbiBjaHVua3MpCgpkaXN0cmlidXRpb24gPSBkaXN0cmlidXRpb25fY2hlY2soYygtMTIyLjUwLCAzNy40OSwtMTIyLjQ5LCAzNy41MCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDQ19zaGFwZV9zcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNpZXNfc3RhbmRhcmRpemVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZBTFNFKQpgYGAKCmBgYHtyLCBHQklGIFN1bW1hcnksIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBmaWcua2VlcD0nYWxsJ30KIyMjR0JJRiBTdW1tYXJ5IyMjCiNPcmdhbml6ZSB0aGUgR0JJRiBhbmFseXNpcyBvdXRwdXQKCmQgPSBkaXN0cmlidXRpb24KUFAgPSBkW1sxXV0kY29uZmlybWVkCkNDID0gZFtbMl1dJGNvbmZpcm1lZApyYW5nZSA9IGRbWzNdXSRjb25maXJtZWQKbm9fZGF0YSA9IGRbWzNdXSRub19kYXRhCgpkZl9QUCA9IGMoKQpkZl9DQyA9IGMoKQpkZl9yYW5nZSA9IGMoKQpkZl9ub19kYXRhID0gYygpCmRmX25vdF9pbl9HQklGID0gYygpCgpmb3IgKHMgaW4gc3BlY2llc19ib3RoJHNwZWNpZXMpIHsKICBpZiAoaXMubmEocykpIHsKICAgIGRmX25vdF9pbl9HQklGID0gYXBwZW5kKGRmX25vdF9pbl9HQklGLCBUUlVFKQogICAgZGZfUFAgPSBhcHBlbmQoZGZfUFAsIE5BKQogICAgZGZfQ0MgPSBhcHBlbmQoZGZfQ0MsIE5BKQogICAgZGZfcmFuZ2UgPSBhcHBlbmQoZGZfcmFuZ2UsIE5BKQogICAgZGZfbm9fZGF0YSA9IGFwcGVuZChkZl9ub19kYXRhLCBOQSkKICAgIG5leHQKICB9IGVsc2UgewogICAgZGZfbm90X2luX0dCSUYgPSBhcHBlbmQoZGZfbm90X2luX0dCSUYsIEZBTFNFKQogIH0KICAKICBpZiAocyAlaW4lIFBQKSB7CiAgICBkZl9QUCA9IGFwcGVuZChkZl9QUCwgVFJVRSkKICB9IGVsc2UgewogICAgZGZfUFAgPSBhcHBlbmQoZGZfUFAsIEZBTFNFKQogIH0KICAKICBpZiAocyAlaW4lIENDKSB7CiAgICBkZl9DQyA9IGFwcGVuZChkZl9DQywgVFJVRSkKICB9IGVsc2UgewogICAgZGZfQ0MgPSBhcHBlbmQoZGZfQ0MsIEZBTFNFKQogIH0KICAKICBpZiAocyAlaW4lIHJhbmdlKSB7CiAgICBkZl9yYW5nZSA9IGFwcGVuZChkZl9yYW5nZSwgVFJVRSkKICB9IGVsc2UgewogICAgZGZfcmFuZ2UgPSBhcHBlbmQoZGZfcmFuZ2UsIEZBTFNFKQogIH0KICAKICBpZiAocyAlaW4lIG5vX2RhdGEpIHsKICAgIGRmX25vX2RhdGEgPSBhcHBlbmQoZGZfbm9fZGF0YSwgVFJVRSkKICB9IGVsc2UgewogICAgZGZfbm9fZGF0YSA9IGFwcGVuZChkZl9ub19kYXRhLCBGQUxTRSkKICB9CiAgCn0KCkdCSUZfc3VtbWFyeSA9IGRhdGEuZnJhbWUoCiAgU3BlY2llcyA9IHNwZWNpZXNfYm90aCR2ZXJiYXRpbV9uYW1lLAogIEdCSUZTcGVjaWVzID0gc3BlY2llc19ib3RoJHNwZWNpZXMsCiAgUGlsbGFyUG9pbnRPY2N1cnJlbmNlID0gZGZfUFAsCiAgQ0NTT2NjdXJyZW5jZSA9IGRmX0NDLAogIFJhbmdlID0gZGZfcmFuZ2UsCiAgTm9EYXRhID0gZGZfbm9fZGF0YSwKICBOb3RJbkdCSUYgPSBkZl9ub3RfaW5fR0JJRgopCgpwZXJjZW50YWdlcyA9IEdCSUZfc3VtbWFyeSAlPiUKICBncm91cF9ieShhY3Jvc3MoUGlsbGFyUG9pbnRPY2N1cnJlbmNlOk5vdEluR0JJRikpICU+JQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShwZXIgPSBjb3VudCAvIHN1bShjb3VudCkpCgprbm93bl9zdW1tYXJ5ID0gYXMubnVtZXJpYyhHQklGX3N1bW1hcnkgJT4lIGZpbHRlcighaXMubmEoR0JJRlNwZWNpZXMpKSAlPiUgc3VtbWFyaXNlKGNvdW50ID0gc3VtKFJhbmdlID09IFRSVUUgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ0NTT2NjdXJyZW5jZSA9PSBUUlVFKSkpCgpgYGAKCkZvY3VzZWQgb24ganVzdCB0aGUgYHIgc2FtcGxlc2AgKGBzYW1wbGVzYCkgc2FtcGxlcywgd2UgcmVtb3ZlZCBzaW5nbGV0b25zIGFuZCBhbGwgYHIgb3ZlcmxhcGAgKGBvdmVybGFwYCkgQVNWcyB0aGF0IG92ZXJsYXBwZWQgd2l0aCBuZWdhdGl2ZSBjb250cm9scyAoU3VwcGxlbWVudGFsIEluZm9ybWF0aW9uIFgpLCBhbmQgd2UgcmFyZWZpZWQgc2FtcGxlcyB0byB0aGUgbWluaW11bSBudW1iZXIgb2YgcmVhZHMgb2YgYW55IHNhbXBsZSwgbGVhdmluZyBgciBwcm9jZXNzZWRfQVNWc2AgKGBwcm9jZXNzZWRfQVNWc2ApIEFTVnMgYW5kIGByIHByb2Nlc3NlZF9yZWFkc2AgKGBwcm9jZXNzZWRfcmVhZHNgKSByZWFkcy4gYHIgc3ByaW50ZigiJTAuMWYlJSIsIHVuYXNzaWduZWRfQVNWc1t1bmFzc2lnbmVkX0FTVnMkS2luZ2RvbSA9PSAiIixdJGZyZXEgKiAxMDApYCAoYHNwcmludGYoIiUwLjFmJSUiLCB1bmFzc2lnbmVkX0FTVnNbdW5hc3NpZ25lZF9BU1ZzJEtpbmdkb20gPT0gIiIsXSRmcmVxICogMTAwKWApIG9mIEFTVnMgd2VyZSB1bmFzc2lnbmVkLCBhbmQgdGhlIHJlbWFpbmRlciBpbmNsdWRlZCByZXByZXNlbnRhdGl2ZXMgZnJvbSBgciB1bmlxdWVbIlBoeWx1bSJdYCAoYHVuaXF1ZVsiUGh5bHVtIl1gKSBwaHlsYSwgYHIgdW5pcXVlWyJDbGFzcyJdYCAoYHVuaXF1ZVsiQ2xhc3MiXWApIGNsYXNzZXMsIGByIHVuaXF1ZVsiT3JkZXIiXWAgKGB1bmlxdWVbIk9yZGVyIl1gKSBvcmRlcnMsIGByIHVuaXF1ZVsiRmFtaWx5Il1gIChgdW5pcXVlWyJGYW1pbHkiXWApIGZhbWlsaWVzLCBgciB1bmlxdWVbIkdlbnVzIl1gIChgdW5pcXVlWyJHZW51cyJdYCkgZ2VuZXJhLCBhbmQgYHIgdW5pcXVlWyJTcGVjaWVzIl1gIChgdW5pcXVlWyJTcGVjaWVzIl1gKSBzcGVjaWVzIChGaWd1cmUgNCkuIEEgYnJlYWtkb3duIG9mIHRoZSByZWxhdGl2ZSBwcm9wb3J0aW9ucyBvZiByZWFkcyBhbmQgQVNWcyBhc3NpZ25lZCB0byBlYWNoIHBoeWxhIGNhbiBiZSBmb3VuZCBpbiBUYWJsZSAxLiBUbyBlbnN1cmUgdGhlIGFjY3VyYWN5IG9mIHRoZXNlIHRheG9ub21pYyBpZGVudGlmaWNhdGlvbnMsIHdlIGNvbmZpcm1lZCB0aGF0IGByIGtub3duX3N1bW1hcnlgIChga25vd25fc3VtbWFyeWApIG9mIGByIHVuaXF1ZVsiU3BlY2llcyJdYCAoYHVuaXF1ZVsiU3BlY2llcyJdYCkgaWRlbnRpZmllZCBzcGVjaWVzIChgciBzcHJpbnRmKCIlMC4xZiUlIiwga25vd25fc3VtbWFyeS91bmlxdWVbIlNwZWNpZXMiXSAqIDEwMClgIGBzcHJpbnRmKCIlMC4xZiUlIiwga25vd25fc3VtbWFyeS91bmlxdWVbIlNwZWNpZXMiXSAqIDEwMClgKSBoYXZlIG9jY3VycmVuY2UgcmVjb3JkcyBpbiB0aGUgQ2FsaWZvcm5pYSBDdXJyZW50IFN5c3RlbSAoQ0NTKSBhbmQga25vd24gcmFuZ2VzIHRoYXQgZW5jb21wYXNzIFBpbGxhciBQb2ludC4gKGFkZGl0aW9uYWwgZGV0YWlscyBpbiBTSSAxIGFuZCBUYWJsZSBTMikuCgpgYGB7ciwgVGFibGUgMX0KIyMjVEFCTEUgMSMjIwojQ3JlYXRlIHRhYmxlIHdpdGggc3VtbWFyeSBvZiByZWFkcywgQVNWcywgYW5kIHNwZWNpZXMgYnkgcGh5bGEKCiNSZW1vdmUgYWxsIHVuY2xhc3NpZmllZCBBU1ZzIGFuZCBjb25kZW5zZSB0byBwaHlsdW0gbGV2ZWwKcGh5c2VxX3RvdGFscmVhZHMgPSB0YXhfZ2xvbShwaHlzZXFfc3VtbWVkLCB0YXhyYW5rID0gIlBoeWx1bSIsIE5Bcm0gPSBUUlVFKQpQaHlsYV9SZWFkcyA9IGRhdGEuZnJhbWUoUGh5bGEgPSB0YXhfdGFibGUocGh5c2VxX3RvdGFscmVhZHMpWywgMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICBSZWFkcyA9IHJvd1N1bXMob3R1X3RhYmxlKHBoeXNlcV90b3RhbHJlYWRzKSkpCgpwaHlzZXFfdG90YWxBU1ZzID0gcGh5c2VxX3N1bW1lZAoKb3R1X3RhYmxlKHBoeXNlcV90b3RhbEFTVnMpW290dV90YWJsZShwaHlzZXFfdG90YWxBU1ZzKSA+IDBdIDwtIDEKcGh5c2VxX3RvdGFsQVNWcyA9IHRheF9nbG9tKHBoeXNlcV90b3RhbEFTVnMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGF4cmFuayA9ICJQaHlsdW0iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5Bcm0gPVRSVUUpCgpQaHlsYV9BU1ZzID0gZGF0YS5mcmFtZShQaHlsYSA9IHRheF90YWJsZShwaHlzZXFfdG90YWxBU1ZzKVssIDJdLAogICAgICAgICAgICAgICAgICAgICAgICBBU1ZzID0gcm93U3VtcyhvdHVfdGFibGUocGh5c2VxX3RvdGFsQVNWcykpKQoKcGh5c2VxX3NwZWNpZXNieXBoeWxhID0gcGh5c2VxX3N1bW1lZApwaHlzZXFfc3BlY2llc2J5dGF4YSA9IHRheF9nbG9tKHBoeXNlcV9zdW1tZWQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRheHJhbmsgPSAiU3BlY2llcyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5Bcm0gPSBUUlVFKQpvdHVfdGFibGUocGh5c2VxX3NwZWNpZXNieXRheGEpW290dV90YWJsZShwaHlzZXFfc3BlY2llc2J5dGF4YSkgPiAwXSA8LSAxCnBoeXNlcV9zcGVjaWVzYnl0YXhhID0gdGF4X2dsb20ocGh5c2VxX3NwZWNpZXNieXRheGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRheHJhbmsgPSAiUGh5bHVtIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkFybSA9IFRSVUUpCgpQaHlsYV9TcGVjaWVzID0gIGRhdGEuZnJhbWUoUGh5bGEgPSB0YXhfdGFibGUocGh5c2VxX3NwZWNpZXNieXRheGEpWywgMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTcGVjaWVzID0gcm93U3VtcyhvdHVfdGFibGUocGh5c2VxX3NwZWNpZXNieXRheGEpKSkKCmxpc3QgPSBsaXN0KFBoeWxhX1JlYWRzLCBQaHlsYV9BU1ZzLCBQaHlsYV9TcGVjaWVzKQpmdWxsID0gbGlzdCAlPiUgcmVkdWNlKGZ1bGxfam9pbiwgYnkgPSAnUGh5bHVtJykKZnVsbFtpcy5uYShmdWxsKV0gPC0gMAoKZnVsbF9zb3J0ZWQgPSBmdWxsW29yZGVyKC1mdWxsJFJlYWRzKSwgXQoKZnVsbF9zb3J0ZWQgPSBmdWxsX3NvcnRlZCAlPiUKICBtdXRhdGUoUmVhZHNfUGVyY2VudCA9IHNjYWxlczo6bGFiZWxfcGVyY2VudCgpKFJlYWRzIC8gc3VtKFJlYWRzKSkpICU+JQogIG11dGF0ZShBU1ZzX1BlcmNlbnQgPSBzY2FsZXM6OmxhYmVsX3BlcmNlbnQoKShBU1ZzIC8gc3VtKEFTVnMpKSkgJT4lCiAgbXV0YXRlKFNwZWNpZXNfUGVyY2VudCA9IHNjYWxlczo6bGFiZWxfcGVyY2VudCgpKFNwZWNpZXMgLyBzdW0oU3BlY2llcykpKQoKZnVsbF9zb3J0ZWQkUGh5bHVtID0gcmVtb3ZlX05DQkludW1zKGZ1bGxfc29ydGVkJFBoeWx1bSkKZnVsbF9zb3J0ZWQkUGh5bHVtID0gc3RyX3JlcGxhY2UoZnVsbF9zb3J0ZWQkUGh5bHVtLCAicGh5bHVtXyIsICJDbGFzczogIikKCmNvbF9vcmRlciA9IGMoCiAgIlBoeWx1bSIsCiAgIlJlYWRzIiwKICAiUmVhZHNfUGVyY2VudCIsCiAgIkFTVnMiLAogICJBU1ZzX1BlcmNlbnQiLAogICJTcGVjaWVzIiwKICAiU3BlY2llc19QZXJjZW50IgopCgpmdWxsX3NvcnRlZCA9IGZ1bGxfc29ydGVkWywgY29sX29yZGVyXQoKd3JpdGUuY3N2KGZ1bGxfc29ydGVkLCAiQW5hbHlzaXMgUHJvZHVjdHMvVGFibGUxLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKZnVsbF9zb3J0ZWQKYGBgCgpgYGB7ciBGaWd1cmUgNCAtLSBQaHlsb2dlbmV0aWMgVHJlZSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIHJlc3VsdHMgPSBGQUxTRSwgZXJyb3IgPSBGQUxTRX0KIyMjRmlndXJlIDQjIyMKI0NyZWF0ZSBwaHlsb2dlbmV0aWMgdHJlZSBmb3IgYWxsIHRheG9ub21pYyBhc3NpZ25tZW50cwoKb3B0aW9ucyhnZXRDbGFzcy5tc2cgPSBGQUxTRSkKCiNBZ2dyZWdhdGUgdG8gc3BlY2llcyBhc3NpZ25tZW50IGFuZCByZW1vdmUgdGhlIE5DQkkgaWRlbnRpZmllcnMKcHRfcGh5c2VxID0gdGF4X2dsb20oZGF0YV9waHlzZXEsIHRheHJhbmsgPSAiU3BlY2llcyIsIE5Bcm0gPSBGQUxTRSkKdGF4X3RhYmxlKHB0X3BoeXNlcSkgPSB0YXhfdGFibGUocHRfcGh5c2VxKVshdGF4X3RhYmxlKHB0X3BoeXNlcSlbLCAiS2luZ2RvbSJdID09ICIiXQp0YXhfdGFibGUocHRfcGh5c2VxKVt0YXhfdGFibGUocHRfcGh5c2VxKSA9PSAiIl0gPSBOQQp0YXhfdGFibGUocHRfcGh5c2VxKSA9IHRheF90YWJsZShwdF9waHlzZXEpWyFpcy5uYSh0YXhfdGFibGUocHRfcGh5c2VxKVssICJQaHlsdW0iXSldCm51bWJlcnMgPSBzdWIoIi4qXyIsICIiLCB0YXhfdGFibGUocHRfcGh5c2VxKSkKCnRheGEgPSBhcHBseShudW1iZXJzLCAxLCBmdW5jdGlvbih4KSB0YWlsKG5hLm9taXQoeCksIDEpKQoKdGF4X3RhYmxlKHB0X3BoeXNlcSkgPSByZW1vdmVfTkNCSW51bXModGF4X3RhYmxlKHB0X3BoeXNlcSkpCgp0YXhhX2NsYXNzaWZpY2F0aW9uID0gY2xhc3NpZmljYXRpb24odGF4YSwgZGIgPSAibmNiaSIpCgp0YXhhX3RyZWUgPSBjbGFzczJ0cmVlKHRheGFfY2xhc3NpZmljYXRpb24sIGNoZWNrID0gVFJVRSkKCiNDaGFuZ2UgdGhlIHRpcCBsYWJlbHMgdG8gbWF0Y2ggcGh5bG9zZXEgb2JqZWN0cyAoY29kZSBvbmx5IHdvcmtzIGlmIG9yZGVyIGlzIHRoZSBzYW1lKQp0YXhhX3RyZWUkcGh5bG8kdGlwLmxhYmVsID0gcm93Lm5hbWVzKHRheF90YWJsZShwdF9waHlzZXEpKQoKcGh5bGEgPSB1bmlxdWUodGF4X3RhYmxlKHB0X3BoeXNlcSlbLCAiUGh5bHVtIl0pCgpwaHlsYV9ub2RlcyA9IGMoKQpwaHlsYV9ub2RlcyA9IGRhdGEuZnJhbWUoIm5vZGVfcGh5bHVtIiA9IGMoKSwgIm5vZGUiID0gYygpKQpwaHlsYV9ub2Rlc19zZWNvbmRhcnkgPSBkYXRhLmZyYW1lKCJub2RlX3BoeWx1bSIgPSBjKCksICJ0aXBzIiA9IGMoKSkKCmZvciAoeCBpbiBwaHlsYSkgewogIE9UVXMgPSBuYS5vbWl0KHJvdy5uYW1lcyh0YXhfdGFibGUocHRfcGh5c2VxKSlbdGF4X3RhYmxlKHB0X3BoeXNlcSlbLCAiUGh5bHVtIl0gPT0geF0pCiAgT1RVcyA9IGFzLnZlY3RvcihPVFVzKQogIG51bSA9IGFwZTo6Z2V0TVJDQSh0YXhhX3RyZWUkcGh5bG8sIHRpcCA9IE9UVXMpCiAgaWYgKGlzLm51bGwobnVtKSkgewogICAgbm9kZXMgPSBhc190aWJibGUodGF4YV90cmVlJHBoeWxvKQogICAgbnVtID0gbm9kZXMkbm9kZVtub2RlcyRsYWJlbCA9PSBPVFVzXQogIH0KICBkZiA9IGRhdGEuZnJhbWUoIm5vZGVfcGh5bHVtIiA9IGMoeCksICJub2RlIiA9IGMobnVtKSkKICBwaHlsYV9ub2RlcyA9IHJiaW5kKHBoeWxhX25vZGVzLCBkZikKICAKICBpZiAobGVuZ3RoKE9UVXMpIDwgNikgewogICAgZm9yICh5IGluIE9UVXMpIHsKICAgICAgZGYyID0gZGF0YS5mcmFtZSgibm9kZV9waHlsdW0iID0gYyh4KSwgInRpcHMiID0gYyh5KSkKICAgICAgcGh5bGFfbm9kZXNfc2Vjb25kYXJ5ID0gcmJpbmQocGh5bGFfbm9kZXNfc2Vjb25kYXJ5LCBkZjIpCiAgICB9CiAgfQp9CgpwdF9waHlzZXEgPSBtZXJnZV9waHlsb3NlcShwdF9waHlzZXEsIHRheGFfdHJlZSRwaHlsbykKCiNVc2UgUG9seWNocm9tZSBwYWNrYWdlIHRvIGNyZWF0ZSBhIGdvb2QgY29sb3IgcGFsZXR0ZSBmb3IgdGhlIG51bWJlciBvZiBwaHlsYQpzZXQuc2VlZCg1Njc2MjkpCmNvbG9ycyA9IGNyZWF0ZVBhbGV0dGUoCiAgMjgsCiAgYygiI0ZGRkZGRiIpLAogIHJhbmdlID0gYygzMCwgODApLAogIHRhcmdldCA9IGMoIm5vcm1hbCIsICJwcm90YW5vcGUiLCAiZGV1dGVyYW5vcGUiLCAidHJpdGFub3BlIikKKQoKI0NoZWNrIHdoZXRoZXIgdGhlIGdpdmVuIG9yZGVyIG9mIGNvbG9ycyBoYXMgZ29vZCBjb250cmFzdCBmb3IgZGlmZmVyZW50IGZvcm1zIG9mIGNvbG9yYmxpbmRuZXNzCnBhbC5zYWZlKGNvbG9ycykKCiNNYW51YWxseSByZS1vcmRlciB0aGUgY29sb3JzIHRvIGVuc3VyZSB0aGVyZSBpcyBnb29kIGNvbnRyYXN0IGJldHdlZW4gYWRqYWNlbnQgY29sb3JzCmNvbG9yc19vcmRlcmVkID0gY29sb3JzW2MoCiAgJ05DMicsCiAgJ05DMTEnLAogICdOQzI3JywKICAnTkMyNScsCiAgJ05DNCcsCiAgJ05DNScsCiAgJ05DOCcsCiAgJ05DMjQnLAogICdOQzknLAogICdOQzEwJywKICAnTkMxMicsCiAgJ05DMTMnLAogICdOQzEnLAogICdOQzE0JywKICAnTkMxNScsCiAgJ05DMTYnLAogICdOQzcnLAogICdOQzE3JywKICAnTkMxOCcsCiAgJ05DMTknLAogICdOQzIwJywKICAnTkMyMScsCiAgJ05DMjInLAogICdOQzIzJywKICAnTkMyNicsCiAgJ05DNicsCiAgJ05DMycsCiAgJ05DMjgnCildCgojQ29uZmlybSB0aGF0IHRoZSBuZXcgb3JkZXIgd29ya3Mgd2VsbApwYWwuc2FmZShjb2xvcnNfb3JkZXJlZCkKCiNDcmVhdGUgZ2d0cmVlCnAgPC0gZ2d0cmVlOjpnZ3RyZWUocHRfcGh5c2VxLCAgbGF5b3V0ID0gImNpcmN1bGFyIikKCm9yZGVyZWRfbmFtZXMgPSBnZ3RyZWU6OmdldF90YXhhX25hbWUocCkKb3JkZXJlZF9uYW1lcyA9IHVuaXF1ZShvcmRlcmVkX25hbWVzKQpvcmRlcmVkX25hbWVzW21hdGNoKHJvd25hbWVzKHRheF90YWJsZShwdF9waHlzZXEpKSwgb3JkZXJlZF9uYW1lcyldID0gdGF4X3RhYmxlKHB0X3BoeXNlcSlbLCAiUGh5bHVtIl0Kb3JkZXJlZF9uYW1lcyA9IHVuaXF1ZShvcmRlcmVkX25hbWVzKQoKbmFtZXMoY29sb3JzX29yZGVyZWQpID0gb3JkZXJlZF9uYW1lcwoKcCA9IHAgKyBnZW9tX2ZydWl0KAogIGdlb20gPSBnZW9tX3RpbGUsCiAgbWFwcGluZyA9IGFlcyhmaWxsID0gUGh5bHVtKSwKICB3aWR0aCA9IDMsCiAgc2hvdy5sZWdlbmQgPSBGQUxTRQopICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvcnNfb3JkZXJlZCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvcnNfb3JkZXJlZCkKCnAgPSBwICsgIGdlb21fZnJ1aXQoCiAgZGF0YSA9IHBoeWxhX25vZGVzX3NlY29uZGFyeSwKICBnZW9tID0gZ2VvbV90aWxlLAogIG1hcHBpbmcgPSBhZXMoeSA9IHRpcHMsIGZpbGwgPSBub2RlX3BoeWx1bSksCiAgd2lkdGggPSA2LAogIHNob3cubGVnZW5kID0gRkFMU0UKKQpwID0gcCArIGdndHJlZTo6Z2VvbV9oaWxpZ2h0KAogIGRhdGEgPSBwaHlsYV9ub2RlcywKICBtYXBwaW5nID0gYWVzKG5vZGUgPSBub2RlLCBmaWxsID0gbm9kZV9waHlsdW0pLAogIHNob3cubGVnZW5kID0gRkFMU0UKKQoKcCA9IHAgKyBnZ3RyZWU6Omdlb21fY2xhZGVsYWIoCiAgZGF0YSA9IHBoeWxhX25vZGVzLAogIG1hcHBpbmcgPSBhZXMobm9kZSA9IG5vZGUsIGxhYmVsID0gbm9kZV9waHlsdW0pLAogIGdlb20gPSAidGV4dCIsCiAgYW5nbGUgPSAiYXV0byIsCiAgb2Zmc2V0ID0gNSwKICBmb250c2l6ZSA9IDIsCiAgYmFyY29sb3IgPSBOQSwKICBzaG93LmxlZ2VuZCA9IEZBTFNFCikKCnAgPSBwICsKICB0aGVtZSgKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICd0cmFuc3BhcmVudCcpLAogICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAndHJhbnNwYXJlbnQnLCBjb2xvciA9IE5BKSwKICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICd0cmFuc3BhcmVudCcpLAogICAgbGVnZW5kLmJveC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAndHJhbnNwYXJlbnQnKQogICkKCnBhdGggPSAiRmlndXJlcy9GaWd1cmU0LiIKc2F2ZV9wZGZfcG5nKAogIHBsb3QgPSBwLAogIHBhdGggPSBwYXRoLAogIHcgPSAxNjksCiAgaCA9IDE2OSwKICB1ID0gIm1tIiwKICBiZyA9ICJ0cmFuc3BhcmVudCIsCiAgZHBpID0gNjAwCikKCmBgYAoKPGNlbnRlcj4KCiFbKkZpZ3VyZSA0OiA6IFBoeWxvZ2VuZXRpYyB0cmVlIGNvbG9yZWQgYnkgdGhlIHBoeWxhIGlkZW50aWZpZWQgYWNyb3NzIGFsbCBlRE5BIHNhbXBsZXMuIEl0YWxpY2l6ZWQgdGF4b25vbWljIG5hbWVzIGFyZSB0aG9zZSB3aXRoIG5vIHBoeWx1bS1sZXZlbCBhc3NpZ25tZW50LCBzbyBjbGFzcy1sZXZlbCBhc3NpZ25tZW50cyBhcmUgdXNlZCB0byBkaWZmZXJlbnRpYXRlIChhZGRpdGlvbmFsIGluZm9ybWF0aW9uIGFkZGVkIGFmdGVyIFIgZmlndXJlIHByb2R1Y3Rpb24pKl0oYHIgcGFzdGUwKHBhdGgsICJwbmciKWApCgo8L2NlbnRlcj4KCiMjIyMgMy4yIEluZGl2aWR1YWwtTGV2ZWwgRGlmZmVyZW5jZXMgQmV0d2VlbiBMb2NhdGlvbnMKCmBgYHtyIEV1bGVyIERpYWdyYW1zfQojIyNFdWxlciBEaWFncmFtcyMjIwoKZXVsZXJyX29wdGlvbnMocXVhbnRpdGllcyA9IGxpc3QoZm9udHNpemUgPSAxMCksCiAgICAgICAgICAgICAgIGxlZ2VuZCA9IGxpc3QoZm9udHNpemUgPSAxNCkpCgojU3Vic2V0IGFtcHZpczIgZGF0YSBieSBsb2NhdGlvbgoKYW1wX1MxID0gYW1wX2ZpbHRlcl9zYW1wbGVzKGRhdGFfYW1wLCBMb2NhdGlvbiAlaW4lIGMoIlMxIikpCmFtcF9TMiA9IGFtcF9maWx0ZXJfc2FtcGxlcyhkYXRhX2FtcCwgTG9jYXRpb24gJWluJSBjKCJTMiIpKQphbXBfTiA9IGFtcF9maWx0ZXJfc2FtcGxlcyhkYXRhX2FtcCwgTG9jYXRpb24gJWluJSBjKCJOIikpCgojTGlzdCB0aGUgdW5pcXVlIHRheGEgYXQgZWFjaCBsb2NhdGlvbgoKUzFfdGF4YSA9IHVuaXF1ZShhbXBfUzEkdGF4JFNwZWNpZXMpClMxX3RheGEgPSBTMV90YXhhW1MxX3RheGEgIT0gIiJdClMyX3RheGEgPSB1bmlxdWUoYW1wX1MyJHRheCRTcGVjaWVzKQpTMl90YXhhID0gUzJfdGF4YVtTMl90YXhhICE9ICIiXQpOX3RheGEgPSB1bmlxdWUoYW1wX04kdGF4JFNwZWNpZXMpCk5fdGF4YSA9IE5fdGF4YVtOX3RheGEgIT0gIiJdCgojTGlzdCB0aGUgdW5pcXVlIEFTVnMgYXQgZWFjaCBsb2NhdG9uCgpTMV9BU1YgPSB1bmlxdWUoYW1wX1MxJHRheCRPVFUpClMyX0FTViA9IHVuaXF1ZShhbXBfUzIkdGF4JE9UVSkKTl9BU1YgPSB1bmlxdWUoYW1wX04kdGF4JE9UVSkKCiNVc2luZyBldWxlcnIsIGNyZWF0ZSBldWxlciBkaWFncmFtcyBmb3IgdGF4YSBhbmQgQVNWcwoKYWRkX3F1YW50aXR5X2xpbmVfYnJlYWsgPSBmdW5jdGlvbih2KSB7CiAgdGFncyA8LQogICAgdiRjaGlsZHJlbiRjYW52YXMuZ3JvYiRjaGlsZHJlbiRkaWFncmFtLmdyb2IuMSRjaGlsZHJlbiR0YWdzJGNoaWxkcmVuCiAgCiAgdGFncyA8LSBkby5jYWxsKGdyaWQ6OmdMaXN0LCBsYXBwbHkodGFncywgZnVuY3Rpb24oeCkgewogICAgeCRjaGlsZHJlbltbMl1dJGxhYmVsIDwtIHN1YigiIFxcJSkiLCAiJSkiLCB4JGNoaWxkcmVuW1syXV0kbGFiZWwpCiAgICBiZWZvcmUgPSBnc3ViKCIgLiokIiwgIiIsIHgkY2hpbGRyZW5bWzJdXSRsYWJlbCkKICAgIGFmdGVyID0gZ3N1YigiLipcXCgiLCAiKCIsIHgkY2hpbGRyZW5bWzJdXSRsYWJlbCkKICAgIGZ1bGwgPSBicXVvdGUoYXRvcChOQSwgYXRvcChhdG9wKAogICAgICB0ZXh0c3R5bGUoLihiZWZvcmUpKSwgdGV4dHN0eWxlKGl0YWxpYyguKGFmdGVyKSkpCiAgICApLCBOQSkpKQogICAgCiAgICB4JGNoaWxkcmVuW1syXV0kbGFiZWwgPC0gZnVsbAogICAgeCRjaGlsZHJlbltbMl1dJGp1c3QgPC0gTlVMTAogICAgeAogIH0pKQogIAogIHYkY2hpbGRyZW4kY2FudmFzLmdyb2IkY2hpbGRyZW4kZGlhZ3JhbS5ncm9iLjEkY2hpbGRyZW4kdGFncyA8LQogICAgdGFncwogIAogIHJldHVybih2KQp9CgpFX3RheGEgPC0KICBldWxlcihsaXN0KFMxID0gUzFfdGF4YSwgUzIgPSBTMl90YXhhLCBOID0gTl90YXhhKSwgc2hhcGUgPSAiZWxsaXBzZSIpCkVfdGF4YV9wbG90ID0gcGxvdCgKICBFX3RheGEsCiAgcXVhbnRpdGllcyA9IGxpc3QodHlwZSA9IGMoImNvdW50cyIsICJwZXJjZW50IiksIGNleCA9IDEpLAogIGxlZ2VuZCA9IGxpc3QoCiAgICBzaWRlID0gInJpZ2h0IiwKICAgIG5yb3cgPSAxLAogICAgbmNvbCA9IDMsCiAgICBjZXggPSAxCiAgKQopCkVfdGF4YV9wbG90ID0gYWRkX3F1YW50aXR5X2xpbmVfYnJlYWsoRV90YXhhX3Bsb3QpCgp1bmlxdWVfdGF4YV9sb2NhdGlvbiA8LSAoRV90YXhhJG9yaWdpbmFsLnZhbHVlc1siUzEiXSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgIEVfdGF4YSRvcmlnaW5hbC52YWx1ZXNbIlMyIl0gKwogICAgICAgICAgICAgICAgICAgICAgICAgICBFX3RheGEkb3JpZ2luYWwudmFsdWVzWyJOIl0pIC8gc3VtKEVfdGF4YSRvcmlnaW5hbC52YWx1ZXMpCgoKRV9BU1YgPC0KICBldWxlcihsaXN0KFMxID0gUzFfQVNWLCBTMiA9IFMyX0FTViwgTiA9IE5fQVNWKSwgc2hhcGUgPSAiZWxsaXBzZSIpCkVfQVNWX3Bsb3QgPSBwbG90KAogIEVfQVNWLAogIHF1YW50aXRpZXMgPSBsaXN0KHR5cGUgPSBjKCJjb3VudHMiLCAicGVyY2VudCIpLCBjZXggPSAxKSwKICBsZWdlbmQgPSBsaXN0KAogICAgc2lkZSA9ICJyaWdodCIsCiAgICBucm93ID0gMSwKICAgIG5jb2wgPSAzLAogICAgY2V4ID0gMQogICkKKQpFX0FTVl9wbG90ID0gYWRkX3F1YW50aXR5X2xpbmVfYnJlYWsoRV9BU1ZfcGxvdCkKCnVuaXF1ZV9BU1ZfbG9jYXRpb24gPC0gKEVfQVNWJG9yaWdpbmFsLnZhbHVlc1siUzEiXSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgRV9BU1Ykb3JpZ2luYWwudmFsdWVzWyJTMiJdICsKICAgICAgICAgICAgICAgICAgICAgICAgICBFX0FTViRvcmlnaW5hbC52YWx1ZXNbIk4iXSkgLyBzdW0oRV9BU1Ykb3JpZ2luYWwudmFsdWVzKQoKYGBgCgpBY3Jvc3MgYm90aCB0YXhhIChuPWBgYCByIHVuaXF1ZVsiU3BlY2llcyJdYGB1bmlxdWVbIlNwZWNpZXMiXSBgYGApIGFuZCBBU1ZzIChuPWByIHByb2Nlc3NlZF9BU1ZzYCBgcHJvY2Vzc2VkX0FTVnNgKSwgYWxsIHRocmVlIGxvY2F0aW9ucyBoYWQgdW5pcXVlIGVsZW1lbnRzLCBzdWdnZXN0aW5nIHRoYXQgdGhlcmUgd2FzIG5vdCBjb21wbGV0ZSBtaXhpbmcgb2YgZUROQSBhY3Jvc3MgbWljcm8taGFiaXRhdHMuIGByIHNwcmludGYoIiUwLjFmJSUiLCB1bmlxdWVfdGF4YV9sb2NhdGlvbiAqIDEwMClgIGBzcHJpbnRmKCIlMC4xZiUlIiwgdW5pcXVlX3RheGFfbG9jYXRpb24gKiAxMDApYCBvZiB0YXhhIGFuZCBgciBzcHJpbnRmKCIlMC4xZiUlIiwgdW5pcXVlX0FTVl9sb2NhdGlvbiAqIDEwMClgIGBzcHJpbnRmKCIlMC4xZiUlIiwgdW5pcXVlX0FTVl9sb2NhdGlvbiAqIDEwMClgIG9mIEFTVnMgd2VyZSB1bmlxdWUgdG8gb25lIG9mIHRoZSB0aHJlZSBsb2NhdGlvbnMgKEZpZ3VyZSA1KS4gQXQgYm90aCB0aGUgdGF4YSBhbmQgQVNWIGxldmVsLCBTMSBoYWQgbW9yZSB1bmlxdWUgZWxlbWVudHMgdGhhbiBTMiBhbmQgbmVhcnNob3JlLCBhbHRob3VnaCB0aGlzIGVmZmVjdCB3YXMgbW9yZSBwcm9ub3VuY2VkIGFjcm9zcyBBU1ZzLiBBU1ZzIGFuZCB0YXhhIHNoYXJlZCBhY3Jvc3MgcGFpcnMgb2YgdHdvIGxvY2F0aW9ucyB3ZXJlIHRoZSBsZWFzdCBjb21tb24gZWxlbWVudHMuCgpgYGB7ciBGaWd1cmUgNX0KCmV1bGVyID0gKHdyYXBfZWxlbWVudHMocGFuZWwgPSBncmlkOjp0ZXh0R3JvYigKICAnQSknLAogIGhqdXN0ID0gNiwKICB2anVzdCA9IDEsCiAgZ3AgPSBncGFyKGZvbnRzaXplID0gMTQsIGZvbnRmYWNlID0gJ2JvbGQnKQopKSArCiAgd3JhcF9lbGVtZW50cyAocGFuZWwgPSBncmlkOjp0ZXh0R3JvYigKICAgICdCKScsCiAgICBoanVzdCA9IDYsCiAgICB2anVzdCA9IDEsCiAgICBncCA9IGdwYXIoZm9udHNpemUgPSAxNCwgZm9udGZhY2UgPSAnYm9sZCcpCiAgKSkpIC8KICAoCiAgICB3cmFwX2VsZW1lbnRzKHBhbmVsID0gRV90YXhhX3Bsb3QkY2hpbGRyZW4kY2FudmFzLmdyb2IpICsgd3JhcF9lbGVtZW50cyhwYW5lbCA9IEVfQVNWX3Bsb3QkY2hpbGRyZW4kY2FudmFzLmdyb2IpCiAgKSAvCiAgd3JhcF9lbGVtZW50cyhwYW5lbCA9IEVfdGF4YV9wbG90JGNoaWxkcmVuJGxlZ2VuZC5ncm9iKSArIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEsIDEwLCAxKSkKCnBhdGggPSAiRmlndXJlcy9GaWd1cmU1LiIKc2F2ZV9wZGZfcG5nKAogIHBsb3QgPSBldWxlciwKICBwYXRoID0gcGF0aCwKICB3ID0gMTY5LAogIGggPSAxMTAsCiAgdSA9ICJtbSIsCiAgYmcgPSAidHJhbnNwYXJlbnQiLAogIGRwaSA9IDYwMAopCmBgYAoKPGNlbnRlcj4KCiFbKkZpZ3VyZSA1OiBBcmVhLXByb3BvcnRpb25hbCBFdWxlciBkaWFncmFtcyBzaG93aW5nIHRoZSBvdmVybGFwIGluIHRheGEgKEEpIGFuZCBBU1ZzIChCKSBiZXR3ZWVuIGxvY2F0aW9ucyBTMSwgUzIsIGFuZCBOLipdKGByIHBhc3RlMChwYXRoLCAicG5nIilgKQoKPC9jZW50ZXI+CgpgYGB7ciBJbmRpY2F0b3IgU3BlY2llcyBBbmFseXNpcywgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFfQojIyNJbmRpY2F0b3IgU3BlY2llcyBBbmFseXNpcyMjIwoKI0Z1bmN0aW9uIGZvciBjcmVhdGluZyBpbmRpY2F0b3Igc3BlY2llcyBoZWF0bWFwIGZyb20gcGh5c2VxIGRhdGEKCmluZGljYXRvcl9oZWF0bWFwIDwtIGZ1bmN0aW9uKHBoeXNlcSwgYXN2KSB7CiAgI0lmIGFuYWx5emluZyBieSB0YXhhLCByZW1vdmUgYWxsIHVuY2xhc3NpZmllZCBBU1ZzIGFuZCBjb25kZW5zZSB0byBzcGVjaWVzIGFzc2lnbm1lbnRzCiAgaWYgKGFzdiA9PSBGQUxTRSkgewogICAgcGh5c2VxID0gdGF4X2dsb20ocGh5c2VxLCB0YXhyYW5rID0gIlNwZWNpZXMiLCBOQXJtID0gVFJVRSkKICAgIHRheF90YWJsZShwaHlzZXEpID0gcmVtb3ZlX05DQkludW1zKHRheF90YWJsZShwaHlzZXEpKQogIH0gZWxzZSB7CiAgICB0YXhfdGFibGUocGh5c2VxKSA9IHJlbW92ZV9OQ0JJbnVtcyh0YXhfdGFibGUocGh5c2VxKSkKICB9CiAgCiAgI0NvbnZlcnQgdG8gcHJlc2VuY2UvYWJzZW5jZSBkYXRhCiAgb3R1X3RhYmxlKHBoeXNlcSlbb3R1X3RhYmxlKHBoeXNlcSkgPiAwXSA8LSAxCiAgCiAgI1VzZSBpbmRpY3NwZWNpZXMgcGFja2FnZSB0byBnZXQgdG9wIHRheGEKICBpbmR2YWwgPSBtdWx0aXBhdHQoCiAgICB0KG90dV90YWJsZShwaHlzZXEpKSwKICAgIHQoc2FtcGxlX2RhdGEocGh5c2VxKVssICJMb2NhdGlvbiJdKSwKICAgIGNvbnRyb2wgPSBob3cobnBlcm0gPSA5OTkpLAogICAgZHVsZWcgPSBUUlVFCiAgKQogIAogIHRvcF9OID0gcm93bmFtZXMoaW5kdmFsJHNpZ24gJT4lIAogICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocC52YWx1ZSA8IDAuMDUpICU+JSAKICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHMuTiA9PSAxKSAgJT4lIAogICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoc3RhdCA+IC43KSkKICB0b3BfUzEgPSByb3duYW1lcyhpbmR2YWwkc2lnbiAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocC52YWx1ZSA8IDAuMDUpICU+JSAKICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihzLlMxID09IDEpICAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoc3RhdCA+IC43KSkKICB0b3BfUzIgPSByb3duYW1lcyhpbmR2YWwkc2lnbiAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocC52YWx1ZSA8IDAuMDUpICU+JSAKICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihzLlMyID09IDEpICAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoc3RhdCA+IC43KSkKICAKICBpbmRpY2F0b3JzX2FsbCA9IGModG9wX04sIHRvcF9TMSwgdG9wX1MyKQogIAogICNNZXJnZSBzYW1wbGVzIGJ5IHNpdGUvdGltZSBiZWZvcmUgcGxvdHRpbmcKICBwaHlzZXFfbWVyZ2UgPSBtZXJnZV9zYW1wbGVzKHBoeXNlcSwgIlNpdGVCeVRpbWUiKQogIAogICNVcGRhdGUgbWV0YWRhdGEgYWNjb3JkaW5nbHkKICB1cGRhdGVkX21ldGFkYXRhID0gYXMubWF0cml4KHNhbXBsZV9kYXRhKHBoeXNlcSlbLCBjKCJTaXRlQnlUaW1lIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGltZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxvY2F0aW9uIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlMiKV0pCiAgdXBkYXRlZF9tZXRhZGF0YSA9IGFzLmRhdGEuZnJhbWUodXBkYXRlZF9tZXRhZGF0YSkKICB1cGRhdGVkX21ldGFkYXRhJFNpdGVCeVRpbWUgPSBhcy5mYWN0b3IodXBkYXRlZF9tZXRhZGF0YSRTaXRlQnlUaW1lKQogIHVwZGF0ZWRfbWV0YWRhdGEkVGltZSA9IGFzLmZhY3Rvcih1cGRhdGVkX21ldGFkYXRhJFRpbWUpCiAgdXBkYXRlZF9tZXRhZGF0YSRMb2NhdGlvbiA9IGFzLmZhY3Rvcih1cGRhdGVkX21ldGFkYXRhJExvY2F0aW9uKQogIHVwZGF0ZWRfbWV0YWRhdGEgPSBkaXN0aW5jdCh1cGRhdGVkX21ldGFkYXRhKQogIHJvd25hbWVzKHVwZGF0ZWRfbWV0YWRhdGEpID0gdXBkYXRlZF9tZXRhZGF0YVssICdTaXRlQnlUaW1lJ10KICBzYW1wbGVfZGF0YShwaHlzZXFfbWVyZ2UpIDwtIHNhbXBsZV9kYXRhKHVwZGF0ZWRfbWV0YWRhdGEpCiAgCiAgI0RpdmlkZSBhbGwgbWVyZ2VkIHNhbXBsZXMgYnkgdGhlIG51bWJlciBvZiBzYW1wbGVzIHRoZXkgcmVwcmVzZW50CiAgb3R1X3RhYmxlKHBoeXNlcV9tZXJnZSkgPSBvdHVfdGFibGUocGh5c2VxX21lcmdlKSAvIDMKICAKICBvdHVfdGFibGUocGh5c2VxX21lcmdlKVtncmVwbCgnMTE6MzAnLCByb3duYW1lcyhvdHVfdGFibGUocGh5c2VxX21lcmdlKSkpXSA9IG90dV90YWJsZShwaHlzZXFfbWVyZ2UpW2dyZXBsKCcxMTozMCcsIHJvd25hbWVzKG90dV90YWJsZShwaHlzZXFfbWVyZ2UpKSldIC8KICAgIDMKICAKICBvdHVfdGFibGUocGh5c2VxX21lcmdlKVtncmVwbCgnMTQ6MDAnLCByb3duYW1lcyhvdHVfdGFibGUocGh5c2VxX21lcmdlKSkpXSA9IG90dV90YWJsZShwaHlzZXFfbWVyZ2UpW2dyZXBsKCcxNDowMCcsIHJvd25hbWVzKG90dV90YWJsZShwaHlzZXFfbWVyZ2UpKSldIC8KICAgIDMKICAKICBvdHVfdGFibGUocGh5c2VxX21lcmdlKVtncmVwbCgnMTc6MDAnLCByb3duYW1lcyhvdHVfdGFibGUocGh5c2VxX21lcmdlKSkpXSA9IG90dV90YWJsZShwaHlzZXFfbWVyZ2UpW2dyZXBsKCcxNzowMCcsIHJvd25hbWVzKG90dV90YWJsZShwaHlzZXFfbWVyZ2UpKSldIC8KICAgIDMKICAKICAjQWRkIGxhYmVscyB0byB0aGUgaW5kaWNhdG9yIHNwZWNpZXMgZm9yIHBsb3R0aW5nCiAgaW5kaWNhdG9yc19vbmx5IDwtCiAgICBwcnVuZV90YXhhKGNvbG5hbWVzKG90dV90YWJsZShwaHlzZXFfbWVyZ2UpKSAlaW4lIGluZGljYXRvcnNfYWxsLCBwaHlzZXFfbWVyZ2UpCiAgCiAgYWRkX2luZGljYXRvcl9sYWJlbCA8LSBmdW5jdGlvbihYKSB7CiAgICBpZiAoWCAlaW4lIHRvcF9OKSB7CiAgICAgIHJldHVybigiTiIpCiAgICB9CiAgICBlbHNlIGlmIChYICVpbiUgdG9wX1MxKSB7CiAgICAgIHJldHVybigiUzEiKQogICAgfQogICAgZWxzZSBpZiAoWCAlaW4lIHRvcF9TMikgewogICAgICByZXR1cm4gKCJTMiIpCiAgICB9CiAgICBlbHNlIHsKICAgICAgcmV0dXJuKCJOQSIpCiAgICB9CiAgfQogIAogIGluZGljYXRvcnMgPC0KICAgIHNhcHBseShyb3duYW1lcyh0YXhfdGFibGUoaW5kaWNhdG9yc19vbmx5KSksIGFkZF9pbmRpY2F0b3JfbGFiZWwpCiAgCiAgdGF4X3RhYmxlKGluZGljYXRvcnNfb25seSkgPSBjYmluZCh0YXhfdGFibGUoaW5kaWNhdG9yc19vbmx5KSwgaW5kaWNhdG9ycykKICAKICAjUGxvdAogIHBsb3QgPSBwbG90X2hlYXRtYXAoCiAgICBpbmRpY2F0b3JzX29ubHksCiAgICBtZXRob2QgPSBOVUxMLAogICAgZGlzdGFuY2UgPSBOVUxMLAogICAgdHJhbnMgPSBOVUxMLAogICAgdGF4YS5vcmRlciA9IHJldihpbmRpY2F0b3JzX2FsbCksCiAgICB0YXhhLmxhYmVsID0gIlNwZWNpZXMiLAogICAgc2FtcGxlLmxhYmVsID0gIlRpbWUiLAogICAgc2FtcGxlLm9yZGVyID0gIlRpbWUiCiAgKSArCiAgICBmYWNldF9ncmlkKAogICAgICBmYWN0b3IoaW5kaWNhdG9ycywgbGV2ZWxzID0gYygnUzEnLCAnUzInLCAnTicpKSB+IGZhY3RvcihMb2NhdGlvbiwgbGV2ZWxzID0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCdTMScsICdTMicsICdOJykpLAogICAgICBzY2FsZXMgPSAiZnJlZSIsCiAgICAgIHNwYWNlID0gImZyZWUiLAogICAgICBzd2l0Y2ggPSAieSIKICAgICkgKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAiYmxhY2siLCBoaWdoID0gIiNCNUQ3RTQiKSArCiAgICB0aGVtZV9ncmV5KGJhc2Vfc2l6ZSA9IDEwKSArCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoCiAgICAgIGFuZ2xlID0gNDUsCiAgICAgIHZqdXN0ID0gMSwKICAgICAgaGp1c3QgPSAxCiAgICApKSArCiAgICB0aGVtZShzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIpICArCiAgICB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMSkpKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogICAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnMoZmlsbCA9ICJQcm9wb3J0aW9uIG9mIFBvc2l0aXZlIERldGVjdHMiLCB0aXRsZSA9ICJMb2NhdGlvbnMiKSArCiAgICB0aGVtZSgKICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIpLAogICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJibGFjayIsIGZhY2UgPSAiaXRhbGljIiksCiAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIikKICAgICkgKwogICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9jb2xvcmJhcihiYXJ3aWR0aCA9IDEwKSkKICAKICBwbG90JHNjYWxlcyRzY2FsZXNbWzJdXSRuYW1lIDwtICJJbmRpY2F0b3JzIgogIAogIHJldHVybigKICAgIGxpc3QoCiAgICAgIHBsb3QgPSBwbG90LAogICAgICB0b3BfTiA9IHRvcF9OLAogICAgICB0b3BfUzEgPSB0b3BfUzEsCiAgICAgIHRvcF9TMiA9IHRvcF9TMiwKICAgICAgYWxsX2luZGljYXRvcnMgPSBpbmRpY2F0b3JzX2FsbCwKICAgICAgZnVsbF9vdXRwdXQgPSBpbmR2YWwKICAgICkKICApCn0KCmhlYXRtYXBfdGF4YSA9IGluZGljYXRvcl9oZWF0bWFwKGRhdGFfcGh5c2VxLCBGQUxTRSkKaGVhdG1hcF9BU1YgPSBpbmRpY2F0b3JfaGVhdG1hcChkYXRhX3BoeXNlcSwgVFJVRSkKCmluZGljYXRvcl9BU1ZzID0gZGF0YV9hbXAkdGF4W2hlYXRtYXBfQVNWJGFsbF9pbmRpY2F0b3JzLCBdCnVuYXNzaWduZWRfaW5kaWNhdG9yX0FTVnMgPSBpbmRpY2F0b3JfQVNWcyAlPiUgCiAgZ3JvdXBfYnkoS2luZ2RvbSkgJT4lIAogIHN1bW1hcmlzZShuID0gbigpKSAlPiUgCiAgbXV0YXRlIChmcmVxID0gbiAvIHN1bShuKSkKCmlkZW50aWZ5X25ld19pbmRpY2F0b3JzID0gZnVuY3Rpb24oZGF0YV9hbXAsIHRvcF9BU1ZzLCB0b3BfdGF4YSkgewogIHRvcF9BU1ZzID0gZGF0YV9hbXAkdGF4W3RvcF9BU1ZzLCBdCiAgdG9wX3RheGEgPSBkYXRhX2FtcCR0YXhbdG9wX3RheGEsIF0KICAKICB0b3BfQVNWcyA9IHRvcF9BU1ZzJFNwZWNpZXNbdG9wX0FTVnMkU3BlY2llcyAhPSAiIl0KICB0b3BfdGF4YSA9IHRvcF90YXhhJFNwZWNpZXMKICAKICB0b3BfQVNWcyA9IHJlbW92ZV9OQ0JJbnVtcyh0b3BfQVNWcykKICB0b3BfdGF4YSA9IHJlbW92ZV9OQ0JJbnVtcyh0b3BfdGF4YSkKICByZXR1cm4oc2V0ZGlmZih0b3BfQVNWcywgdG9wX3RheGEpKQp9CgpOX0FTVl9leHRyYSA9IHNvcnQoaWRlbnRpZnlfbmV3X2luZGljYXRvcnMoZGF0YV9hbXAsIGhlYXRtYXBfQVNWJHRvcF9OLCBoZWF0bWFwX3RheGEkdG9wX04pKQpTMV9BU1ZfZXh0cmEgPSBzb3J0KGlkZW50aWZ5X25ld19pbmRpY2F0b3JzKGRhdGFfYW1wLCBoZWF0bWFwX0FTViR0b3BfUzEsIGhlYXRtYXBfdGF4YSR0b3BfUzEpKQpTMl9BU1ZfZXh0cmEgPSBzb3J0KGlkZW50aWZ5X25ld19pbmRpY2F0b3JzKGRhdGFfYW1wLCBoZWF0bWFwX0FTViR0b3BfUzIsIGhlYXRtYXBfdGF4YSR0b3BfUzIpKQoKYGBgCgpgYGB7ciBGaWd1cmUgNn0KcGF0aCA9ICJGaWd1cmVzL0ZpZ3VyZTYuIgpzYXZlX3BkZl9wbmcoCiAgcGxvdCA9IGhlYXRtYXBfdGF4YSRwbG90LAogIHBhdGggPSBwYXRoLAogIHcgPSAxNjksCiAgaCA9IDEwMCwKICB1ID0gIm1tIiwKICBiZyA9ICJ0cmFuc3BhcmVudCIsCiAgZHBpID0gNjAwCikKYGBgCgo8Y2VudGVyPgoKIVsqRmlndXJlIDY6IEhlYXQgbWFwIG9mIGlkZW50aWZpZWQgaW5kaWNhdG9yIHRheGEgZm9yIGFsbCB0aHJlZSBsb2NhdGlvbnMgb3ZlciB0aW1lLCBzY2FsZWQgYnkgdGhlIG51bWJlciBvZiByZXBsaWNhdGVzIHRoYXQgZGV0ZWN0ZWQgdGhhdCBzcGVjaWVzLipdKGByIHBhc3RlMChwYXRoLCAicG5nIilgKQoKPC9jZW50ZXI+CgpVc2luZyBhbiBpbmRpY2F0b3Igc3BlY2llcyBmcmFtZXdvcmsgcHJvZHVjZWQgc2ltaWxhciB0cmVuZHMgdG8gdGhlIGFuYWx5c2lzIG9mIHVuaXF1ZSB0YXhhIGFuZCBBU1ZzOyBhbGwgdGhyZWUgbG9jYXRpb25zIGhhZCBpbmRpY2F0b3IgdGF4YSBhbmQgQVNWcywgYW5kIFMxIGhhZCBtb3JlIGluZGljYXRvciBlbGVtZW50cyB0aGFuIG90aGVyIGxvY2F0aW9ucy4gQnkgdGF4YSwgd2UgaWRlbnRpZmllZCBgciBsZW5ndGgoaGVhdG1hcF90YXhhJGFsbF9pbmRpY2F0b3JzKWAgYGxlbmd0aChoZWF0bWFwX3RheGEkYWxsX2luZGljYXRvcnMpYCBpbmRpY2F0b3IgdGF4YTogYHIgbGVuZ3RoKGhlYXRtYXBfdGF4YSR0b3BfUzEpYCBgbGVuZ3RoKGhlYXRtYXBfdGF4YSR0b3BfUzEpYCBmb3IgUzEsIGByIGxlbmd0aChoZWF0bWFwX3RheGEkdG9wX1MyKWAgYGxlbmd0aChoZWF0bWFwX3RheGEkdG9wX1MyKWAgZm9yIFMyLCBhbmQgYHIgbGVuZ3RoKGhlYXRtYXBfdGF4YSR0b3BfTilgIGBsZW5ndGgoaGVhdG1hcF90YXhhJHRvcF9OKWAgZm9yIG5lYXJzaG9yZSAoRmlndXJlIDYpLiBCeSBBU1ZzLCB3ZSBmb3VuZCBtb3JlIGluZGljYXRvcnMgb3ZlcmFsbC4gV2UgaWRlbnRpZmllZCBgciBsZW5ndGgoaGVhdG1hcF9BU1YkYWxsX2luZGljYXRvcnMpYCBgbGVuZ3RoKGhlYXRtYXBfQVNWJGFsbF9pbmRpY2F0b3JzKWAgaW5kaWNhdG9yIEFTVnM6IGByIGxlbmd0aChoZWF0bWFwX0FTViR0b3BfUzEpYCBgbGVuZ3RoKGhlYXRtYXBfQVNWJHRvcF9TMSlgIGZvciBTMSwgYHIgbGVuZ3RoKGhlYXRtYXBfQVNWJHRvcF9TMilgIGBsZW5ndGgoaGVhdG1hcF9BU1YkdG9wX1MyKWAgZm9yIFMyLCBhbmQgYHIgbGVuZ3RoKGhlYXRtYXBfQVNWJHRvcF9OKWAgYGxlbmd0aChoZWF0bWFwX0FTViR0b3BfTilgIGZvciBuZWFyc2hvcmUgKFN1cHBsZW1lbnRhbCBGaWd1cmUgWCkuIE1vc3QgKGByIHNwcmludGYoIiUwLjFmJSUiLCB1bmFzc2lnbmVkX2luZGljYXRvcl9BU1ZzW3VuYXNzaWduZWRfaW5kaWNhdG9yX0FTVnMkS2luZ2RvbSA9PSAiIixdJGZyZXEgKiAxMDApYCBgc3ByaW50ZigiJTAuMWYlJSIsIHVuYXNzaWduZWRfaW5kaWNhdG9yX0FTVnNbdW5hc3NpZ25lZF9pbmRpY2F0b3JfQVNWcyRLaW5nZG9tID09ICIiLF0kZnJlcSAqIDEwMClgKSBpbmRpY2F0b3IgQVNWcyBoYWQgbm8gdGF4b25vbWljIGFzc2lnbm1lbnQsIGJ1dCB0aGUgb25lcyB0aGF0IGRpZCBpbmNsdWRlZCBzZXZlcmFsIHNwZWNpZXMgYmV5b25kIHRoZSBvcmlnaW5hbCBpbmRpY2F0b3IgdGF4YSwgYXQgUzEgKCpgciB0b1N0cmluZyhTMV9BU1ZfZXh0cmEpYCogYHRvU3RyaW5nKFMxX0FTVl9leHRyYSlgKSwgUzIgKCpgciB0b1N0cmluZyhTMl9BU1ZfZXh0cmEpYCogYHRvU3RyaW5nKFMyX0FTVl9leHRyYSlgKSwgYW5kIG5lYXJzaG9yZSAoKmByIHRvU3RyaW5nKE5fQVNWX2V4dHJhKWAqIGB0b1N0cmluZyhOX0FTVl9leHRyYSlgKS4KCiMjIyMgMy4zLiBDb21tdW5pdHktTGV2ZWwgRGlmZmVyZW5jZXMgYmV0d2VlbiBMb2NhdGlvbnMKCmBgYHtyIEphY2NhcmQgRGlzc2ltaWxhcml0eX0KIyMjSmFjY2FyZCBEaXNzaW1pbGFyaXR5IyMjCgojQ2FsY3VsYXRlIEphY2NhcmQgZGlzc2ltaWxhcml0eSBtYXRyaWNlcwpqYWNjYXJkX2Z1bGwgPSB2ZWdkaXN0KHQoZGF0YV9hbXAkYWJ1bmQpLCBiaW5hcnkgPSBUUlVFLCBtZXRob2QgPSAiamFjY2FyZCIpCmphY2NhcmRfdGF4YSA9IHZlZ2Rpc3QodChkYXRhX2FtcF90YXhhJGFidW5kKSwgYmluYXJ5ID0gVFJVRSwgbWV0aG9kID0gImphY2NhcmQiKQpgYGAKCmBgYHtyIFBFUk1BTk9WQX0KIyMjUEVSTUFOT1ZBIyMjCgpzZXQuc2VlZCgwKQoKI1BFUk1BTk9WQSBvbiBmdWxsIGRhdGEgc2V0CnBlcm11dGVzdChiZXRhZGlzcGVyKGphY2NhcmRfZnVsbCwgZGF0YV9hbXAkbWV0YWRhdGEkTG9jYXRpb24pKQphZG9uaXMyKGphY2NhcmRfZnVsbCB+IExvY2F0aW9uICsgVGltZSArIERlcmVwbGljYXRlZF9TYW1wbGVfTmFtZSwKICAgICAgICBkYXRhID0gZGF0YV9hbXAkbWV0YWRhdGEpCgojUEVSTUFOT1ZBIG9uIHRheGEgZGF0YSBzZXQKcGVybXV0ZXN0KGJldGFkaXNwZXIoamFjY2FyZF90YXhhLCBkYXRhX2FtcF90YXhhJG1ldGFkYXRhJExvY2F0aW9uKSkKYWRvbmlzMihqYWNjYXJkX3RheGEgfiBMb2NhdGlvbiArIFRpbWUgKyBEZXJlcGxpY2F0ZWRfU2FtcGxlX05hbWUsCiAgICAgICAgZGF0YSA9IGRhdGFfYW1wX3RheGEkbWV0YWRhdGEpCgpgYGAKCmBgYHtyIE5NRFMgU2NyZWUsIG1lc3NhZ2U9RkFMU0UsIGNhY2hlID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCByZXN1bHRzID0gRkFMU0V9CiMjI05NRFMgU2NyZWUjIyMKCiNDaGVjayB0aGUgc3RyZXNzIHZzLiBkaW1lbnNpb24gcGxvdAoKIyBGdW5jdGlvbiB0aGF0IHBlcmZvcm1zIGEgTk1EUyBmb3IgMS0xMCBkaW1lbnNpb25zIGFuZCBwbG90cyB0aGUgbnIgb2YgZGltZW5zaW9ucyB2cyB0aGUgc3RyZXNzCk5NRFMuc2NyZWUgPC0KICBmdW5jdGlvbih4KSB7CiAgICAjd2hlcmUgeCBpcyB0aGUgbmFtZSBvZiB0aGUgZGF0YSBmcmFtZSB2YXJpYWJsZQogICAgcGxvdCgKICAgICAgcmVwKDEsIDEwKSwKICAgICAgcmVwbGljYXRlKDEwLCBtZXRhTURTKAogICAgICAgIHgsIGF1dG90cmFuc2Zvcm0gPSBGLCBrID0gMQogICAgICApJHN0cmVzcyksCiAgICAgIHhsaW0gPSBjKDEsIDEwKSwKICAgICAgeWxpbSA9IGMoMCwgMC4zMCksCiAgICAgIHhsYWIgPSAiIyBvZiBEaW1lbnNpb25zIiwKICAgICAgeWxhYiA9ICJTdHJlc3MiLAogICAgICBtYWluID0gIk5NRFMgc3RyZXNzIHBsb3QiCiAgICApCiAgICBmb3IgKGkgaW4gMToxMCkgewogICAgICBwb2ludHMocmVwKGkgKyAxLCAxMCksIHJlcGxpY2F0ZSgxMCwgbWV0YU1EUygKICAgICAgICB4LCBhdXRvdHJhbnNmb3JtID0gRiwgayA9IGkgKyAxCiAgICAgICkkc3RyZXNzKSkKICAgIH0KICB9CgojIFVzZSBOTURTLnNjcmVlIGZ1bmN0aW9uIHRvIGNob29zZSB0aGUgb3B0aW1hbCBuciBvZiBkaW1lbnNpb25zCk5NRFMuc2NyZWUoamFjY2FyZF9mdWxsKQpOTURTLnNjcmVlKGphY2NhcmRfdGF4YSkKYGBgCgpgYGB7ciBQQU0gUHJlcGFyYXRpb24sIG1lc3NhZ2U9RkFMU0UsIGNhY2hlID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCByZXN1bHRzID0gRkFMU0V9CiMjI1BBTSBQcmVwYXJhdGlvbiMjIwoKI0VzdGFibGlzaCBmdW5jdGlvbnMgZm9yIFBBTSBjbHVzdGVyaW5nIGFsZ29yaXRobQoKUEFNX3ZhbGlkYXRpb24gPC0gZnVuY3Rpb24oZGlzdCkgewogIGtfbGlzdCA8LSBjKCkKICBhdmdfc2lsX3dpZHRoIDwtIGMoMCkKICBmb3IgKHggaW4gMToobnJvdyhhcy5tYXRyaXgoZGlzdCkpIC0gMSkpIHsKICAgIFBBTSA9IHBhbShkaXN0LCBrID0geCwgZGlzcyA9IFRSVUUpCiAgICBhdmdfc2lsX3dpZHRoIDwtIGMoYXZnX3NpbF93aWR0aCwgUEFNJHNpbGluZm8kYXZnLndpZHRoKQogICAga19saXN0IDwtIGMoa19saXN0LCB4KQogIH0KICAKICBQQU1fdmFsaWRhdGlvbiA8LQogICAgZGF0YS5mcmFtZSAoayA9IGtfbGlzdCwKICAgICAgICAgICAgICAgIHNpbF93aWR0aCA9IGF2Z19zaWxfd2lkdGgsCiAgICAgICAgICAgICAgICB4X21heCA9IHdoaWNoLm1heChhdmdfc2lsX3dpZHRoKSkKICByZXR1cm4oUEFNX3ZhbGlkYXRpb24pCn0KClBBTV92YWxpZGF0aW9uX3ZpeiA8LSBmdW5jdGlvbihQQU1fdmFsaWRhdGlvbikgewogIHBsb3QgPSBnZ3Bsb3QoZGF0YSA9IFBBTV92YWxpZGF0aW9uLAogICAgICAgICAgICAgICAgYWVzKHggPSBrLCB5ID0gc2lsX3dpZHRoKSkgKwogICAgZ2VvbV9saW5lKCkgKwogICAgZ2VvbV9wb2ludCgpICsKICAgIHhsYWIoIksiKSArCiAgICB5bGFiKCJBdmVyYWdlIFNpbGhvdWV0dGUgV2lkdGgiKSArCiAgICBnZ3RpdGxlKCJDbHVzdGVyIFZhbGlkYXRpb24gdXNpbmcgQXZlcmFnZSBTaWxob3VldHRlIFdpZHRoIikgKwogICAgZ2VvbV9zZWdtZW50KAogICAgICBhZXMoCiAgICAgICAgeCA9IHhfbWF4WzFdLAogICAgICAgIHkgPSAwLAogICAgICAgIHhlbmQgPSB4X21heFsxXSwKICAgICAgICB5ZW5kID0gc2lsX3dpZHRoW3hfbWF4WzFdXSwKICAgICAgICBjb2xvciA9ICJyZWQiCiAgICAgICksCiAgICAgIGxpbmV0eXBlID0gMiwKICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRQogICAgKQogIHJldHVybihwbG90KQp9CgpQQU1fc2lsaG91ZXR0ZV92aXpfMyA8LSBmdW5jdGlvbihQQU0sIHNhbXBsZV9kYXRhKSB7CiAgc2V0LnNlZWQoMCkKICBQQU1fZGYgPSBkYXRhLmZyYW1lKFBBTSRzaWxpbmZvJHdpZHRocykKICBQQU1fZGYgPC0gY2JpbmQoUEFNX2RmLCBYID0gcm93Lm5hbWVzKFBBTV9kZikpCiAgUEFNX2RmIDwtIG1lcmdlKFBBTV9kZiwgc2FtcGxlX2RhdGEsIGJ5ID0gIlgiKQogIFBBTV9kZiRjbHVzdGVyIDwtIGFzLmZhY3RvcihQQU1fZGYkY2x1c3RlcikKICBQQU1fZGYkcmFuZG9tID0gc2FtcGxlKDEwMDAsIHNpemUgPSBucm93KFBBTV9kZiksIHJlcGxhY2UgPSBGQUxTRSkKICAKICBnZ3Bsb3QoZGF0YSA9IFBBTV9kZiwKICAgICAgICAgYWVzKAogICAgICAgICAgIHggPSBzaWxfd2lkdGgsCiAgICAgICAgICAgeSA9IHJlb3JkZXIoWCwgcmFuZG9tKSwKICAgICAgICAgICBmaWxsID0gTG9jYXRpb24KICAgICAgICAgKSkgKwogICAgZ2VvbV9wb2ludCgKICAgICAgYWVzKHNoYXBlID0gTG9jYXRpb24sIGNvbG9yID0gVGltZSksCiAgICAgIHNpemUgPSAyLAogICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlciAoaGVpZ2h0ID0gMjAsIHdpZHRoID0gMCkKICAgICkgKwogICAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMTYsIDE1LCAxNykpICsKICAgIGZhY2V0X2dyaWQoY2x1c3RlciB+IC4sIHNjYWxlcyA9ICJmcmVlX3kiLCBzcGFjZSA9ICJmcmVlX3kiKSArCiAgICB2aXJpZGlzOjpzY2FsZV9jb2xvcl92aXJpZGlzKAogICAgICBkaXNjcmV0ZSA9IFRSVUUsCiAgICAgIGJlZ2luID0gMCwKICAgICAgZW5kID0gLjk3LAogICAgICBkaXJlY3Rpb24gPSAtMQogICAgKSArCiAgICB4bGFiKCJTaWxob3VldHRlIFdpZHRoIikgKwogICAgeWxhYigiIikgKwogICAgZ2VvbV92bGluZSAoCiAgICAgIHhpbnRlcmNlcHQgPSBQQU0kc2lsaW5mbyRhdmcud2lkdGgsCiAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIsCiAgICAgIGNvbG9yID0gInJlZCIKICAgICkgKwogICAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxMCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwKSkgKwogICAgZ2d0aXRsZSgiUEFNIENsdXN0ZXJpbmcgVmlzdWFsaXphdGlvbiIpICsKICAgIHRoZW1lKAogICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoCiAgICAgICAgY29sb3VyID0gImJsYWNrIiwKICAgICAgICBzaXplID0gMSwKICAgICAgICBmaWxsID0gTkEKICAgICAgKQogICAgKSArCiAgICBzY2FsZV95X2Rpc2NyZXRlKGV4cGFuZCA9IGV4cGFuc2lvbihhZGQgPSA0MCkpCn0KYGBgCgpgYGB7ciBGaWd1cmUgNywgbWVzc2FnZT1GQUxTRSwgY2FjaGUgPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIHJlc3VsdHMgPSBGQUxTRX0KIyMjRmlndXJlIDcjIyMKCk5NRFNfUEFNIDwtIGZ1bmN0aW9uKGFtcCwgamFjY2FyZCwgZGltLCBQQU1fbG9naWNhbCkgewogIHNldC5zZWVkKDApCiAgTk1EUyA9IG1ldGFNRFMoamFjY2FyZCwgZGltLCB0cnltYXggPSAxMDAsIHRpZHkgPSBUUlVFKQogIAogIE5NRFNfc3RyZXNzID0gc3RyZXNzcGxvdChOTURTKQogIAogIGRhdGEuc2NvcmVzIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKE5NRFMpKQogIGRhdGEuc2NvcmVzJFggPC0gcm93bmFtZXMoZGF0YS5zY29yZXMpCiAgZGF0YS5zY29yZXMgPC0gbWVyZ2UoZGF0YS5zY29yZXMsIGFtcCRtZXRhZGF0YSkKICAKICBhbm5vdGF0aW9uczEgPC0gZGF0YS5mcmFtZSgKICAgIHhwb3MgPSBjKEluZiksCiAgICB5cG9zID0gIGMoLUluZiksCiAgICBhbm5vdGF0ZVRleHQgPSBjKHBhc3RlKCJTdHJlc3M6Iiwgcm91bmQoTk1EUyRzdHJlc3MsIDMpKSksCiAgICBoanVzdHZhciA9IGMoMSksCiAgICB2anVzdHZhciA9IGMoLS41KQogICkKICAKICBwbG90MSA9IGdncGxvdChkYXRhID0gZGF0YS5zY29yZXMsIGFlcyh4ID0gTk1EUzEsIHkgPSBOTURTMikpICsKICAgIHRoZW1lX2xpZ2h0KCkgKwogICAgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSBMb2NhdGlvbiwgY29sb3IgPSBUaW1lKSwgc2l6ZSA9IDIpICsKICAgIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDE2LCAxNSwgMTcpKSArCiAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICAgIGdndGl0bGUgKCJBKSBuTk1EUyBPcmRpbmF0aW9uIChKYWNjYXJkIERpc3NpbWlsYXJpdHkpIikgKwogICAgdmlyaWRpczo6c2NhbGVfY29sb3JfdmlyaWRpcygKICAgICAgZGlzY3JldGUgPSBUUlVFLAogICAgICBiZWdpbiA9IDAsCiAgICAgIGVuZCA9IC45NywKICAgICAgZGlyZWN0aW9uID0gLTEKICAgICkgKwogICAgc3RhdF9lbGxpcHNlKAogICAgICBhZXMoZ3JvdXAgPSBMb2NhdGlvbiksCiAgICAgIHR5cGUgPSAidCIsCiAgICAgIGxpbmV0eXBlID0gMiwKICAgICAgYWxwaGEgPSAxCiAgICApCiAgCiAgcGxvdDEgPSBwbG90MSArCiAgICBnZW9tX3RleHQoZGF0YSA9IGFubm90YXRpb25zMSwKICAgICAgICAgICAgICBhZXMoCiAgICAgICAgICAgICAgICB4ID0geHBvcywKICAgICAgICAgICAgICAgIHkgPSB5cG9zLAogICAgICAgICAgICAgICAgaGp1c3QgPSBoanVzdHZhciwKICAgICAgICAgICAgICAgIHZqdXN0ID0gdmp1c3R2YXIsCiAgICAgICAgICAgICAgICBsYWJlbCA9IGFubm90YXRlVGV4dAogICAgICAgICAgICAgICkpICsKICAgIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTApCiAgCiAgaWYgKFBBTV9sb2dpY2FsID09IFRSVUUpIHsKICAgIHZhbGlkYXRlZF9rID0gUEFNX3ZhbGlkYXRpb24oamFjY2FyZCkKICAgIFBBTV92YWxpZGF0aW9uID0gUEFNX3ZhbGlkYXRpb25fdml6KHZhbGlkYXRlZF9rKQogICAgCiAgICBQQU0gPSBwYW0oamFjY2FyZCwgayA9IHZhbGlkYXRlZF9rJHhfbWF4WzFdLCBkaXNzID0gVFJVRSkKICAgIHBsb3QyID0gUEFNX3NpbGhvdWV0dGVfdml6XzMoUEFNLCBhbXAkbWV0YWRhdGEpCiAgICAKICAgIHJldHVybigKICAgICAgbGlzdCgKICAgICAgICBOTURTID0gcGxvdDEsCiAgICAgICAgUEFNID0gcGxvdDIsCiAgICAgICAgTk1EU19zdHJlc3MgPSBOTURTX3N0cmVzcywKICAgICAgICBQQU1fdmFsaWRhdGlvbiA9IFBBTV92YWxpZGF0aW9uCiAgICAgICkKICAgICkKICB9CiAgcmV0dXJuKHBsb3QxKQp9CgpOTURTX1BBTV9mdWxsID0gTk1EU19QQU0oZGF0YV9hbXAsIGphY2NhcmRfZnVsbCwgMiwgVFJVRSkKTk1EU19QQU1fZnVsbCRQQU1fdmFsaWRhdGlvbgoKTk1EU19QQU1fdGF4YSA9IE5NRFNfUEFNKGRhdGFfYW1wX3RheGEsIGphY2NhcmRfdGF4YSwgMiwgVFJVRSkKTk1EU19QQU1fdGF4YSRQQU1fdmFsaWRhdGlvbgoKTk1EU19QQU1fY29tYmluZWQgPSAoTk1EU19QQU1fZnVsbCROTURTICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArIGdndGl0bGUoIkEpIikpICsKICAoTk1EU19QQU1fZnVsbCRQQU0gICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArIGdndGl0bGUoIkIpIikpICsKICAoTk1EU19QQU1fdGF4YSROTURTICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArIGdndGl0bGUoIkMpIikpICsKICAoTk1EU19QQU1fdGF4YSRQQU0gKyBnZ3RpdGxlKCJEKSIpKSArCiAgcGxvdF9sYXlvdXQoZ3VpZGVzID0gJ2NvbGxlY3QnLCB3aWR0aHMgPSBjKDEsIDEpKQoKcGF0aCA9ICJGaWd1cmVzL0ZpZ3VyZTcuIgpzYXZlX3BkZl9wbmcoCiAgcGxvdCA9IE5NRFNfUEFNX2NvbWJpbmVkLAogIHBhdGggPSBwYXRoLAogIHcgPSAxNjksCiAgaCA9IDE2OSwKICB1ID0gIm1tIiwKICBiZyA9ICJ0cmFuc3BhcmVudCIsCiAgZHBpID0gNjAwCikKYGBgCgpDb21tdW5pdHkgY29tcG9zaXRpb24gYWxzbyBkaWZmZXJlZCBhY3Jvc3MgbG9jYXRpb25zLCBhcyBzdXBwb3J0ZWQgYnkgbXVsdGlwbGUgYW5hbHlzZXMuIFZhcmlhdGlvbiBpbiBjb21tdW5pdHkgY29tcG9zaXRpb24gd2FzIHNpZ25pZmljYW50bHkgZXhwbGFpbmVkIGJ5IGxvY2F0aW9uLCBldmVuIHdoZW4gYWNjb3VudGluZyBmb3IgdmFyaWF0aW9uIGR1ZSB0byB0aW1lIG9mIHNhbXBsaW5nIGFuZCB2YXJpYXRpb24gYmV0d2VlbiByZXBsaWNhdGVzIChBU1ZzOiBQRVJNQU5PVkEgcCBcPCAwLjAwMSwgYmV0YWRpc3BlciBwIFw+IDAuMDU7IFRheGE6IFBFUk1BTk9WQSBwIFw8IDAuMDAxLCBiZXRhZGlzcGVyIHAgXD4gMC4wNSkuIEFzIHZpc3VhbGl6ZWQgdXNpbmcgTk1EUyBvcmRpbmF0aW9uLCBTMSBhbmQgUzIgc2FtcGxlcyBjb2xsZWN0ZWQgYXJvdW5kIGxvdyB0aWRlIHdlcmUgbW9zdCBkaXNzaW1pbGFyIGZyb20gdGhlIG9mZnNob3JlIHNhbXBsZXMgKEZpZ3VyZXMgN0EsIDdDKS4gVGhlc2UgcGF0dGVybnMgcGVyc2lzdGVkIGluIHRoZSBvcHRpbWFsIGNsdXN0ZXJzIGlkZW50aWZpZWQgdXNpbmcgdGhlIHBhcnRpdGlvbmluZyBhbW9uZyBtZWRvaWRzIChQQU0pIGFsZ29yaXRobSwgd2l0aG91dCBhc3N1bWluZyBhIHByaW9yaSB0aGF0IGxvY2F0aW9uIGRyaXZlcyB0aGUgY2x1c3RlcnMgKEZpZ3VyZSA3QiwgN0QpLiBXaGVuIGFuYWx5emVkIGJ5IEFTViwgUEFNIGlkZW50aWZpZWQgdGhyZWUgb3B0aW1hbCBjbHVzdGVycywgcHJpbWFyaWx5IGNvbXBvc2VkIG9mOiAxKSBuZWFyc2hvcmUgc2FtcGxlcyB3aXRoIGFkZGl0aW9uYWwgc2FtcGxlcyBmcm9tIFMxIGFuZCBTMiBhdCBlYXJseSB0aW1lIHBvaW50cywgMikgdGhlIHJlbWFpbmluZyBTMSBzYW1wbGVzLCBhbmQgMykgdGhlIHJlbWFpbmluZyBTMiBzYW1wbGVzIChGaWd1cmUgN0IpLiBXaGVuIGFuYWx5emluZyBieSB0YXhhLCBQQU0gYWRkaXRpb25hbGx5IGRpZmZlcmVudGlhdGVkIGJldHdlZW4gc2FtcGxlcyBmcm9tIHRoZSB0aHJlZSBsb2NhdGlvbnMgY29sbGVjdGVkIGF0IGVhcmx5IHRpbWUgcG9pbnRzLiBUaHVzLCBtdWx0aXBsZSBhbmFseXNlcyB3aXRoIGRpZmZlcmVudCBpbml0aWFsIGFzc3VtcHRpb25zIGFsbCBkZW1vbnN0cmF0ZWQgZGlmZmVyZW50aWFibGUgZUROQSBzaWduYWxzIGFjcm9zcyBtaWNyby1oYWJpdGF0cy4KCjxjZW50ZXI+CgohWypGaWd1cmUgNzogOiBPcmRpbmF0aW9uIGFuYWx5c2lzIChOTURTIHVzaW5nIEphY2NhcmQgRGlzdGFuY2U7IEEsIEMpIGFuZCBjbHVzdGVyIGFuYWx5c2lzIChwYXJ0aXRpb25pbmcgYW1vbmcgbWVkb2lkcyB3aXRoIG51bWJlciBvZiBjbHVzdGVycyB2YWxpZGF0ZWQgdG8gbWF4aW1pemUgYXZlcmFnZSBzaWxob3VldHRlIHdpZHRoOyBCLEQpLiBQYW5lbHMgQSAmIEIgYXJlIGFuYWx5emVkIGJ5IEFTViwgYW5kIHBhbmVscyBDICYgRCBhcmUgYW5hbHl6ZWQgYnkgdGF4YS4gOTUlIGNvbmZpZGVuY2UgZWxsaXBzZXMgZm9yIHRoZSBjZW50cm9pZHMgb2YgZWFjaCBsb2NhdGlvbiBiYXNlZCBvbiBhIG11bHRpdmFyaWF0ZSB0LWRpc3RyaWJ1dGlvbiBhcmUgc2hvd24gaW4gdGhlIE5NRFMgb3JkaW5hdGlvbnMgd2l0aCBibGFjayBkYXNoZWQgbGluZXMsIGFuZCBhdmVyYWdlIHNpbGhvdWV0dGUgd2lkdGggaXMgc2hvd24gaW4gY2x1c3RlciBkaWFncmFtcyB3aXRoIGEgcmVkIGRhc2hlZCBsaW5lLipdKGByIHBhc3RlMChwYXRoLCAicG5nIilgKQoKPC9jZW50ZXI+CgpgYGB7ciBGaWd1cmUgOH0KIyMjRmlndXJlIDgjIyMKCmRpc3RtYXQgPC0gYXMubWF0cml4KGphY2NhcmRfZnVsbCkKCiNDYWxjdWxhdGUgUGFpcndpc2UgRGlzc2ltaWxhcml0eSBWYWx1ZXMgV2l0aGluIGFuZCBBY3Jvc3MgU2l0ZXMKCkphY2NhcmQgPSBjKCkKQ29tYm8gPSBjKCkKVGltZSA9IGMoKQpzdW1tYXJ5ID0gZGF0YS5mcmFtZShKYWNjYXJkLCBDb21ibywgVGltZSkKCm9uZSA9IGMoIlMxIiwgIlMyIiwgIk4iLCAiUzEiLCAiUzIiLCAiUzEiKQpvbmVfbmFtZXMgPSBjKCJTMSIsICJTMiIsICJOIiwgIlMxIiwgIlMyIiwgIlMxIikKdHdvID0gYygiUzEiLCAiUzIiLCAiTiIsICJOIiwgIk4iLCAiUzIiKQp0d29fbmFtZXMgPSBjKCJTMSIsICJTMiIsICJOIiwgIk4iLCAiTiIsICJTMiIpCgpmb3IgKHggaW4gbGV2ZWxzKGRhdGFfYW1wJG1ldGFkYXRhJFRpbWUpKSB7CiAgc3Vic2V0ID0gZmlsdGVyKGRhdGFfYW1wJG1ldGFkYXRhLCBkYXRhX2FtcCRtZXRhZGF0YSRUaW1lID09IHgpCiAgCiAgZm9yIChpIGluIDE6bGVuZ3RoKG9uZSkpIHsKICAgIG5hbWUgPSBwYXN0ZShvbmVfbmFtZXNbaV0sIHR3b19uYW1lc1tpXSwgc2VwID0gIjoiKQogICAgZGF0YSA9IGRpc3RtYXRbc3Vic2V0JFhbc3Vic2V0JExvY2F0aW9uID09IG9uZVtpXV0sIHN1YnNldCRYW3N1YnNldCRMb2NhdGlvbiA9PSB0d29baV1dXQogICAgSmFjY2FyZCA9IHZlY3RvcigpCiAgICAKICAgIGlmICghKDAgJWluJSBkaW0oZGF0YSkpKSB7CiAgICAgIGZvciAocm93IGluIDE6bnJvdyhkYXRhKSkgewogICAgICAgIGZvciAoY29sIGluIDE6bmNvbChkYXRhKSkgewogICAgICAgICAgaWYgKGNvbCA+IHJvdykgewogICAgICAgICAgICBKYWNjYXJkID0gYyhKYWNjYXJkLCBkYXRhW3JvdywgY29sXSkKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIENvbWJvIDwtIHJlcChuYW1lLCBsZW5ndGgoSmFjY2FyZCkpCiAgICBUaW1lIDwtIHJlcCh4LCBsZW5ndGgoSmFjY2FyZCkpCiAgICAKICAgIHN1bW1hcnkgPC0gcmJpbmQoc3VtbWFyeSwgZGF0YS5mcmFtZShKYWNjYXJkLCBDb21ibywgVGltZSkpCiAgfQp9CgoKIyNQTE9UVElORwoKI0RlZmluZSBwYWxldHRlIGZvciBjb2xvcnMgYW5kIGZpbGxzCmNvbG9ycyA9IHR1cmJvKDgpCgpwYWxldHRlID0gYygKICAiV2l0aGluIFNpdGUiID0gIiMzMDEyM0JGRiIsCiAgIlMxOk4iID0gIiMxQUU0QjZGRiIgLAogICJTMjpOIiA9ICIjRkFCQTM5RkYiLAogICJTMTpTMiIgPSAiIzdBMDQwM0ZGIgopCgpmaWxsX3BhbGV0dGUgPSBjKAogICJXaXRoaW4gU2l0ZSIgPSAiIzMwMTIzQjIwIiwKICAiUzE6TiIgPSAiIzFBRTRCNjIwIiwKICAiUzI6TiIgPSAiI0ZBQkEzOTIwIiwKICAiUzE6UzIiID0gIiM3QTA0MDMyMCIKKQoKCiNXSVRISU4gU0lURSBDT01CSU5FRAoKc3VtbWFyeSRDb21ibzIgPC0gc3VtbWFyeSRDb21ibwpzdW1tYXJ5JENvbWJvMltzdW1tYXJ5JENvbWJvMiA9PSAiUzE6UzEiXSA9ICJXaXRoaW4gU2l0ZSIKc3VtbWFyeSRDb21ibzJbc3VtbWFyeSRDb21ibzIgPT0gIlMyOlMyIl0gPSAiV2l0aGluIFNpdGUiCnN1bW1hcnkkQ29tYm8yW3N1bW1hcnkkQ29tYm8yID09ICJOOk4iXSA9ICJXaXRoaW4gU2l0ZSIKCnN0YXRzID0gc3VtbWFyeSAlPiUgZmlsdGVyKENvbWJvMiA9PSAiV2l0aGluIFNpdGUiKSAlPiUgc3VtbWFyaXplKG1lYW4gPSBtZWFuKEphY2NhcmQpLCBtYXggPSBtYXgoSmFjY2FyZCkpCgpnMi41ID0gZ2dwbG90KHN1bW1hcnksIGFlcygKICB4ID0gVGltZSwKICB5ID0gSmFjY2FyZCwKICBjb2xvciA9IGZhY3RvcihDb21ibzIsIGxldmVsID0gYygiV2l0aGluIFNpdGUiLCAiUzE6TiIsICJTMjpOIiwgIlMxOlMyIikpLAogIGZpbGwgPSBmYWN0b3IoQ29tYm8yLCBsZXZlbCA9IGMoIldpdGhpbiBTaXRlIiwgIlMxOk4iLCAiUzI6TiIsICJTMTpTMiIpKQopKSArCiAgZ2VvbV9ib3hwbG90KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoLjUsIHByZXNlcnZlID0gInNpbmdsZSIpKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKGRvZGdlLndpZHRoID0gLjUpLCBhbHBoYSA9CiAgICAgICAgICAgICAgIDAuMikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlLCBuYW1lID0gIlNpdGUgUGFpcmluZ3MiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gZmlsbF9wYWxldHRlLCBuYW1lID0gIlNpdGUgUGFpcmluZ3MiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gc3RhdHMkbWVhbiwgY29sb3IgPSBwYWxldHRlWyJXaXRoaW4gU2l0ZSJdKSArCiAgeWxhYigiSmFjY2FyZCBEaXNzaW1pbGFyaXR5IikgKwogIGNvb3JkX2NhcnRlc2lhbihleHBhbmQgPSAwLCBjbGlwID0gIm9mZiIpICsKICBnZW9tX3RleHQoCiAgICBhZXMobWF4KFRpbWUpLAogICAgICAgIHN0YXRzJG1lYW4sCiAgICAgICAgbGFiZWwgPSAiTWVhbiBEaXNzaW1pbGFyaXR5XG4gIFdpdGhpbiBTaXRlcyIsCiAgICAgICAgaGp1c3QgPSAtLjIpLAogICAgY29sb3IgPSBwYWxldHRlWyJXaXRoaW4gU2l0ZSJdLAogICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgIGNoZWNrX292ZXJsYXAgPSBUUlVFCiAgKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxMikgKwogIHRoZW1lKAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIikKICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJ0b3AiKQoKcGF0aCA9ICJGaWd1cmVzL0ZpZ3VyZTguIgpzYXZlX3BkZl9wbmcoCiAgcGxvdCA9IGcyLjUsCiAgcGF0aCA9IHBhdGgsCiAgdyA9IDE2OSwKICBoID0gMTIwLAogIHUgPSAibW0iLAogIGJnID0gInRyYW5zcGFyZW50IiwKICBkcGkgPSA2MDAKKQpgYGAKClRoZSBleHRlbnQgb2YgdGhlIEphY2NhcmQgZGlzc2ltaWxhcml0eSBiZXR3ZWVuIHNhbXBsZXMgZnJvbSBkaWZmZXJlbnQgbG9jYXRpb25zIHZhcmllZCBvdmVyIHRpbWUuIEFzIHNob3duIGluIEZpZ3VyZSA4LCBleGNlcHQgYXQgdGhlIGZpcnN0IHRpbWUgcG9pbnQgc2FtcGxlZCwgdGhlIGRpc3NpbWlsYXJpdHkgYmV0d2VlbiBzYW1wbGVzIGFjcm9zcyBzaXRlcyB3YXMgYWx3YXlzIGdyZWF0ZXIgdGhhbiB0aGUgbWVhbiBkaXNzaW1pbGFyaXR5IGJldHdlZW4gc2FtcGxlcyB3aXRoaW4gdGhlIHNhbWUgc2l0ZSwgYW5kIGluY3JlYXNpbmdseSBzbyBhY3Jvc3MgdGhlIHBlcmlvZCBzYW1wbGVkLiBBdCB0d28gdGltZSBwb2ludHMtLS0xNTozMCBhbmQgMTY6MDAtLS1hZnRlciBsb3cgdGlkZSBidXQgYmVmb3JlIHdhdGVyIHdhcyBtb3ZpbmcgYmV0d2VlbiBhbGwgbG9jYXRpb25zIGFnYWluLCBhbGwgZGlzc2ltaWxhcml0eSB2YWx1ZXMgYWNyb3NzIHNpdGVzIHdlcmUgZ3JlYXRlciB0aGFuIHRoZSBtYXhpbXVtIGRpc3NpbWlsYXJpdHkgcmVjb3JkZWQgYmV0d2VlbiB0d28gc2FtcGxlcyBmcm9tIHRoZSBzYW1lIHNpdGUuCgo8Y2VudGVyPgoKIVsqRmlndXJlIDg6IEJveCBwbG90cyBvdmVyIHRpbWUgc2hvd2luZyB0aGUgcGFpcndpc2UgSmFjY2FyZCBkaXNzaW1pbGFyaXR5IHZhbHVlcyBiZXR3ZWVuIGFsbCB1bmlxdWUgcGFpcnMgb2YgcmVwbGljYXRlcyBmcm9tIHRoZSBzYW1lIHNpdGVzIChXaXRoaW4gU2l0ZSkgYW5kIGFsbCB1bmlxdWUgcGFpcnMgb2Ygc2FtcGxlcyBhY3Jvc3MgdHdvIHNpdGVzIChTMTpPLCBTOk8sIFMxOlMyKS4gVGhlIHNvbGlkIGxpbmUgZGVwaWN0cyB0aGUgbWVhbiBKYWNjYXJkIGRpc3NpbWlsYXJpdHkgdmFsdWUgZnJvbSB3aXRoaW4gc2l0ZSBwYWlyaW5ncy4qXShgciBwYXN0ZTAocGF0aCwgInBuZyIpYCkKCjwvY2VudGVyPgoKIyMjIyAzLjQuIEVjb2xvZ2ljYWwgU2lnbmlmaWNhbmNlCgpgYGB7ciBFY29sb2dpY2FsIFNpZ25pZmljYW5jZSBQcmVwYXJhdGlvbiwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIHJlc3VsdHMgPSBGQUxTRX0KIyMjRWNvbG9naWNhbCBTaWduaWZpY2FuY2UgUHJlcGFyYXRpb24jIyMKCiNDcmVhdGUgZGF0YSBmcmFtZSB3aXRoIHVuaXF1ZSBhbmQgaW5kaWNhdG9yIHNwZWNpZXMgZnJvbSBlYWNoIHNpdGUKUzFfdW5pcXVlID0gc2V0ZGlmZihTMV90YXhhLCB1bmlvbihTMl90YXhhLCBOX3RheGEpKQpTMl91bmlxdWUgPSBzZXRkaWZmKFMyX3RheGEsIHVuaW9uKFMxX3RheGEsIE5fdGF4YSkpCk5fdW5pcXVlID0gc2V0ZGlmZihOX3RheGEsIHVuaW9uKFMyX3RheGEsIFMxX3RheGEpKQoKUzEgPSBkYXRhLmZyYW1lKGxpc3QoU3BlY2llcyA9IHJlbW92ZV9OQ0JJbnVtcyhTMV91bmlxdWUpLCBVbmlxdWUgPSAiUzEiKSkKUzIgPSBkYXRhLmZyYW1lKGxpc3QoU3BlY2llcyA9IHJlbW92ZV9OQ0JJbnVtcyhTMl91bmlxdWUpLCBVbmlxdWUgPSAiUzIiKSkKTiA9IGRhdGEuZnJhbWUobGlzdChTcGVjaWVzID0gcmVtb3ZlX05DQkludW1zKE5fdW5pcXVlKSwgVW5pcXVlID0gIk4iKSkKdW5pcXVlID0gcmJpbmQoUzEsIFMyLCBOKQoKUzFfaSA9IGRhdGEuZnJhbWUobGlzdCgKICBTcGVjaWVzID0gcmVtb3ZlX05DQkludW1zKGRhdGFfYW1wJHRheCRTcGVjaWVzW3Jvd25hbWVzKGRhdGFfYW1wJHRheCkgJWluJSBoZWF0bWFwX3RheGEkdG9wX1MxXSksCiAgSW5kaWNhdG9yID0gIlMxIgopKQpTMl9pID0gZGF0YS5mcmFtZShsaXN0KAogIFNwZWNpZXMgPSByZW1vdmVfTkNCSW51bXMoZGF0YV9hbXAkdGF4JFNwZWNpZXNbcm93bmFtZXMoZGF0YV9hbXAkdGF4KSAlaW4lIGhlYXRtYXBfdGF4YSR0b3BfUzJdKSwKICBJbmRpY2F0b3IgPSAiUzIiCikpCk5faSA9IGRhdGEuZnJhbWUobGlzdCgKICBTcGVjaWVzID0gcmVtb3ZlX05DQkludW1zKGRhdGFfYW1wJHRheCRTcGVjaWVzW3Jvd25hbWVzKGRhdGFfYW1wJHRheCkgJWluJSBoZWF0bWFwX3RheGEkdG9wX05dKSwKICBJbmRpY2F0b3IgPSAiTiIKKSkKaW5kaWNhdG9ycyA9IHJiaW5kKFMxX2ksIFMyX2ksIE5faSkKCmRmX2xpc3QgPSBsaXN0KHVuaXF1ZSwgaW5kaWNhdG9ycykKZnVsbF90YXhhX2xpc3QgPSBkZl9saXN0ICU+JSByZWR1Y2UoZnVsbF9qb2luLCBieSA9ICdTcGVjaWVzJykKCiNJZGVudGlmeSB0YXhvbm9taWMgc3lub255bXMgZm9yIGFsbCBzcGVjaWVzIGluIGFib3ZlIGRhdGEgZnJhbWUKc3lub255bXMgPSBjKCkKZm9yIChzIGluIGZ1bGxfdGF4YV9saXN0JFNwZWNpZXMpIHsKICB3b3Jtc19JRCA9IGdldF93b3Jtc2lkKHMpCiAgaWYgKGlzLm5hKHdvcm1zX0lEKSkgewogICAgc3lucyA9IE5BCiAgfSBlbHNlIHsKICAgIHN5bnMgPSBzeW5vbnltcyh3b3Jtc19JRCwgZGIgPSAnd29ybXMnKQogICAgc3lucyA9IHRvU3RyaW5nKHN5bnNbWzFdXSRzY2llbnRpZmljbmFtZSkKICB9CiAgc3lub255bXMgPSByYmluZChzeW5vbnltcywgc3lucykKfQoKZnVsbF90YXhhX2xpc3QgPSBjYmluZChmdWxsX3RheGFfbGlzdCwgc3lub255bXMpCgojQ2xlYW4gc3BlY2llcyB0ZXh0IGluIGRhdGEgZnJhbWUKCiNSZW1vdmUgYW55dGhpbmcgaW4gcGFyZW50aGV0aWNhbHMKZnVsbF90YXhhX2xpc3Qkc3lub255bXMgPC0KICBnc3ViKCJcXHMqXFwoW15cXCldK1xcKSIsICIiLCBmdWxsX3RheGFfbGlzdCRzeW5vbnltcykKCiNSZW1vdmUgYW55dGhpbmcgYmV5b25kIHR3byB3b3JkcyBpbiBlYWNoIGNvbW1hIHNlcGFyYXRlZCBzZWN0aW9uCmZvciAoc3luIGluIDE6bGVuZ3RoKGZ1bGxfdGF4YV9saXN0JHN5bm9ueW1zKSkgewogIGFsbCA9IHVubGlzdChzdHJzcGxpdChmdWxsX3RheGFfbGlzdCRzeW5vbnltc1tzeW5dLCAiLCIpKQogIGlmICghaXMubmEoYWxsWzFdKSkgewogICAgZm9yIChpIGluIDE6bGVuZ3RoKGFsbCkpIHsKICAgICAgYWxsW2ldID0gc3RyX3RyaW0oYWxsW2ldKQogICAgICBhbGxbaV0gPC0gc3ViKCJeKFxcUypcXHMrXFxTKykuKiIsICJcXDEiLCBhbGxbaV0pCiAgICB9CiAgfQogIHN5bnMgPSB0b1N0cmluZyh1bmlxdWUoYWxsKSkKICBmdWxsX3RheGFfbGlzdCRzeW5vbnltc1tzeW5dID0gc3lucwp9Cgp3cml0ZS5jc3YoZnVsbF90YXhhX2xpc3QsCiAgICAgICAgICAiQW5hbHlzaXMgUHJvZHVjdHMvQlBUX0FuYWx5c2lzLmNzdiIsCiAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgoKYGBge3IgRWNvbG9naWNhbCBTaWduaWZpY2FuY2UgUERGIFJlYWRpbmcsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCByZXN1bHRzID0gRkFMU0V9CiMjI0Vjb2xvZ2ljYWwgU2lnbmlmaWNhbmNlIFBERiBSZWFkaW5nIyMjCgojUmVhZCBpbiBuZWVkZWQgdGV4dCBvZiBCZXR3ZWVuIFBhY2lmaWMgVGlkZXMgKGZpbGVzIG5vdCBnaXZlbiBvbiBHaXRIdWIgZHVlIHRvIGNvcHlyaWdodCkKI1BERnMgb2J0YWluZWQgZnJvbSA1dGggRWRpdGlvbiBvZiBCZXR3ZWVuIFBhY2lmaWMgVGlkZXMgYXZhaWxhYmxlIGRpZ2l0YWxseSB0aHJvdWdoIERlR3J1eXRlcgojTGluayB0byBBY2Nlc3M6IGh0dHBzOi8vZG9pLW9yZy5zdGFuZm9yZC5pZG0ub2NsYy5vcmcvMTAuMTUxNS85NzgxNTAzNjIxMzI5CgojQmV0d2VlblBhY2lmaWNUaWRlc19UZXh0Rm9yU2VhY2hpbmcucGRmIGlzIGEgY29tcGlsYXRpb24gb2YgdGhlIGZvbGxvd2luZyBQREYgc2VjdGlvbnMgZnJvbSBEZUdydXl0ZXIsIGFsaWduZWQgc28gdGhlIFBERiBwYWdlIG51bWJlcnMgbWF0Y2ggdGhlIHRleHQgcGFnZSBudW1iZXJzCiNJbnRyb2R1Y3Rpb24sIDEgT3V0ZXItQ29hc3QgUm9ja3kgU2hvcmVzLCAyIE91dGVyLUNvYXN0IFNhbmR5IEJlYWNoZXMsIDMgT3Blbi1Db2FzdCBSb2NreSBTaG9yZXMsIDQgT3Blbi1Db2FzdCBTYW5keSBCZWFjaGVzLCA1IFJvY2t5IFNob3JlcyBvZiBCYXlzIGFuZCBFc3R1YXJpZXMsIDYgU2FuZCBGbGF0cywgNyBFZWxncmFzcyBGbGF0cywgOCBNdWQgRmxhdHMsIDkgRXhwb3NlZCBQaWxlcywgMTAgUHJvdGVjdGVkIFBpbGVzCgojQmV0d2VlblBhY2lmaWNUaWRlc19UT0MucGRmIGlzIHRoZSBDb250ZW50cyBQREYgc2VjdGlvbiBmcm9tIERlR3J1eXRlcgoKI0NoZWNrIHRvIG9ubHkgcnVuIHRoZXNlIHN0ZXBzIGlmIHlvdSBoYXZlIHRoZSBwcm9wZXIgUERGcyBpbiB5b3VyIERhdGEgZm9sZGVyCmlmIChmaWxlLmV4aXN0cygiRGF0YS9CZXR3ZWVuUGFjaWZpY1RpZGVzX1RleHRGb3JTZWFyY2hpbmcucGRmIikgJgogICAgZmlsZS5leGlzdHMoIkRhdGEvQmV0d2VlblBhY2lmaWNUaWRlc19UT0MucGRmIikpIHsKCiAgdHh0IDwtIHBkZl90ZXh0KCJEYXRhL0JldHdlZW5QYWNpZmljVGlkZXNfVGV4dEZvclNlYXJjaGluZy5wZGYiKQogIHRvYyA8LSBwZGZfdGV4dCgiRGF0YS9CZXR3ZWVuUGFjaWZpY1RpZGVzX1RPQy5wZGYiKQogIAogICNDbGVhbiB1cCBQREYgdGV4dAogIAogICNGaXJzdCByZW1vdmUgcGxhY2VzIHdoZXJlIHRoZXJlJ3MgYSBoeXBoZW4gYWRkZWQgb3ZlciBhIGxpbmUgYnJlYWsgIi1cbiIKICAjVGhlbiByZW1vdmUgYWxsIGxpbmUgYnJlYWtzICJcbiIKICB0eHQgPSBnc3ViKCctXG4nLCAnJywgdHh0KQogIHR4dCA9IGdzdWIoJ1xuJywgJyAnLCB0eHQpCiAgCiAgI0NsZWFuIHVwIFRPQwogIHRvYyA9IHN0cnNwbGl0KHRvYywgIlxuIikKICB0b2MgPSBjKHRvY1tbMV1dLCB0b2NbWzJdXSwgdG9jW1szXV0pCiAgcGFnZV9udW1zID0gZ3JlcGwoIlsxMjM0NTY3ODkwLF0kIiwgdG9jKQogIHRvYyA9IHRvY1twYWdlX251bXNdCiAgCiAgI0ZpeCB0aGUgY291cGxlIG9mIHN0cmluZ3MgdGhhdCBhcmUgc3BsaXQgb3ZlciBtdWx0aXBsZSBsaW5lcwogIHRvY19jbGVhbmVkID0gYyh0b2NbMToxNF0sIHBhc3RlMCh0b2NbMTVdLCB0b2NbMTZdKSwgdG9jWzE3OjIxXSwgcGFzdGUwKHRvY1syMl0sIHRvY1syM10pLCB0b2NbMjQ6NTNdKQogIHRvY19jbGVhbmVkID0gYXMuZGF0YS5mcmFtZSh0b2NfY2xlYW5lZCkKICB0b2NfY2xlYW5lZCA9IGV4dHJhY3QodG9jX2NsZWFuZWQsCiAgICAgICAgICAgICAgICAgICAgICAgIHRvY19jbGVhbmVkLAogICAgICAgICAgICAgICAgICAgICAgICBpbnRvID0gYygndGV4dCcsICdwYWdlJyksCiAgICAgICAgICAgICAgICAgICAgICAgICcoLiopXFxzKyhbXiBdKykkJykKICB0b2NfY2xlYW5lZCRwYWdlID0gYXMubnVtZXJpYyh0b2NfY2xlYW5lZCRwYWdlKQogIAogIHRvY19jbGVhbmVkX21heCA9IHZlY3RvcigpCiAgZm9yICh4IGluIDE6KG5yb3codG9jX2NsZWFuZWQpIC0gMSkpIHsKICAgIGlmICh0b2NfY2xlYW5lZCRwYWdlW3hdID09IHRvY19jbGVhbmVkJHBhZ2VbeCArIDFdKSB7CiAgICAgIHRvY19jbGVhbmVkX21heFt4XSA9IHRvY19jbGVhbmVkJHBhZ2VbeF0KICAgIH0gZWxzZSB7CiAgICAgIHRvY19jbGVhbmVkX21heFt4XSA9IHRvY19jbGVhbmVkJHBhZ2VbeCArIDFdIC0gMQogICAgfQogIH0KICB0b2NfY2xlYW5lZF9tYXhbbnJvdyh0b2NfY2xlYW5lZCldID0gTkEKICAKICB0b2NfY2xlYW5lZCRtYXhfcGFnZSA9IHRvY19jbGVhbmVkX21heAogIAogICNSZW1vdmUgZXZlcnl0aGluZyBub3QgcmVmZXJyaW5nIHRvIHJvY2t5IHNob3JlcwogIHRvY19jbGVhbmVkID0gdG9jX2NsZWFuZWRbMToxNywgXQogIAogICNSZW1vdmUganVzdCByb3dzIHdpdGggem9uZQogIHRvY196b25lcyA9IHRvY19jbGVhbmVkICU+JSBmaWx0ZXIoZ3JlcGwoJ1pvbmUnLCB0ZXh0KSkKICB0b2Nfem9uZXMkdGV4dCA9IGdzdWIoIlxcLi4qIiwgIiIsIHRvY196b25lcyR0ZXh0KQogIHRvY196b25lcyR0ZXh0ID0gdHJpbXdzKHRvY196b25lcyR0ZXh0KQp9CmBgYAoKCmBgYHtyIEVjb2xvZ2ljYWwgU2lnbmlmaWNhbmNlIFRleHQgU2VhcmNoaW5nLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgcmVzdWx0cyA9IEZBTFNFfQojIyNFY29sb2dpY2FsIFNpZ25pZmljYW5jZSBUZXh0IFNlYXJjaGluZyMjIwoKI0NoZWNrIHRvIG9ubHkgcnVuIHRoZXNlIHN0ZXBzIGlmIHlvdSd2ZSBiZWVuIGFibGUgdG8gcHJvcGVybHkgcnVuIHRoZSBhYm92ZSB0ZXh0IGltcG9ydGluZwppZiAoZXhpc3RzKCJ0b2Nfem9uZXMiKSAmIGV4aXN0cygidHh0IikpIHsKICBvdXRwdXQgPSBjKCkKICBmb3IgKHggaW4gMTpsZW5ndGgoZnVsbF90YXhhX2xpc3QkU3BlY2llcykpIHsKICAgIHNwZWNpZXMgPSBmdWxsX3RheGFfbGlzdCRTcGVjaWVzW3hdCiAgICBzeW5vbnltcyA9IGZ1bGxfdGF4YV9saXN0JHN5bm9ueW1zW3hdCiAgICBzeW5vbnltcyA9IHVubGlzdChzdHJzcGxpdChzeW5vbnltcywgIiwgIikpCiAgICBhbGwgPSBjKHNwZWNpZXMsIHN5bm9ueW1zKQogICAgYWxsX2FiYnJldmlhdGVkID0gc3ViKCJbYS16XSogIiwgIi4gIiwgYWxsKQogICAgYWxsX3RvX3NlYXJjaCA9IGMoYWxsLCBhbGxfYWJicmV2aWF0ZWQpCiAgICAKICAgIGFsbF9wYWdlcyA9IHZlY3RvcigpCiAgICBmb3IgKHkgaW4gYWxsX3RvX3NlYXJjaCkgewogICAgICBwYWdlcyA9IGdyZXAoeSwgdHh0LCBpZ25vcmUuY2FzZSA9IEZBTFNFLCBmaXhlZCA9IFRSVUUpCiAgICAgIGFsbF9wYWdlcyA9IGMoYWxsX3BhZ2VzLCBwYWdlcykKICAgIH0KICAgIGFsbF9wYWdlcyA9IHVuaXF1ZShhbGxfcGFnZXMpCiAgICBvdXRwdXRbeF0gPSBsaXN0KGFsbF9wYWdlcykKICB9CiAgCiAgZnVsbF90YXhhX2xpc3QkcGFnZXMgPSBvdXRwdXQKICBmdWxsX3RheGFfbGlzdCRwYWdlc1tzYXBwbHkoZnVsbF90YXhhX2xpc3QkcGFnZXMsIGZ1bmN0aW9uKHgpCiAgICBsZW5ndGgoeCkgPT0gMCldIDwtIE5BCgogIHpvbmVzID0gdW5pcXVlKHRvY196b25lcyR0ZXh0KQogIGRmID0gZGF0YS5mcmFtZShtYXRyaXgobmNvbCA9IGxlbmd0aCh6b25lcyksIG5yb3cgPSAwKSkKICBjb2xuYW1lcyhkZikgPSB6b25lcwogIAogIG5hbWUgPSBjKCkKICB6b25lID0gYygpCiAgcGFnZSA9IGMoKQogIAogIGZvciAoeCBpbiAxOmxlbmd0aChmdWxsX3RheGFfbGlzdCRwYWdlcykpIHsKICAgIGxpc3QgPSBmdWxsX3RheGFfbGlzdCRwYWdlc1tbeF1dCiAgICBpZiAoIWlzLm5hKGxpc3RbMV0pKSB7CiAgICAgIGZvciAoeSBpbiAxOmxlbmd0aChsaXN0KSkgewogICAgICAgIG51bSA9IGxpc3RbeV0KICAgICAgICBmb3IgKHogaW4gMTpsZW5ndGgodG9jX3pvbmVzJHRleHQpKSB7CiAgICAgICAgICBtaW4gPSB0b2Nfem9uZXMkcGFnZVt6XQogICAgICAgICAgbWF4ID0gdG9jX3pvbmVzJG1heFt6XQogICAgICAgICAgaWYgKG51bSA8PSBtYXggJiYgbnVtID49IG1pbikgewogICAgICAgICAgICBuYW1lID0gYXBwZW5kKG5hbWUsIGZ1bGxfdGF4YV9saXN0JFNwZWNpZXNbeF0pCiAgICAgICAgICAgIHpvbmUgPSBhcHBlbmQoem9uZSwgdG9jX3pvbmVzJHRleHRbel0pCiAgICAgICAgICAgIHBhZ2UgPSBhcHBlbmQocGFnZSwgbnVtKQogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgCiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICAKICB9CiAgCiAgZmluYWxfMSA9IGFzLmRhdGEuZnJhbWUoY2JpbmQobmFtZSwgem9uZSwgcGFnZSkpCiAgd3JpdGUuY3N2KGZpbmFsXzEsCiAgICAgICAgICAiQW5hbHlzaXMgUHJvZHVjdHMvQlBUX0FuYWx5c2lzX0ludGVybWVkaWF0ZS5jc3YiLAogICAgICAgICAgcm93Lm5hbWVzID0gRkFMU0UpCn0KYGBgCgoKYGBge3IgRWNvbG9naWNhbCBTaWduaWZpY2FuY2UgQ2xlYW5pbmcgKyBTdGF0aXN0aWNhbCBBbmFseXNpcywgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIHJlc3VsdHMgPSBGQUxTRX0KIyMjRWNvbG9naWNhbCBTaWduaWZpYW5jZSBDbGVhbmluZyArIFN0YXRpc3RpY2FsIEFuYWx5c2lzIyMjCgpmaW5hbF8xID0gcmVhZC5jc3YoIkFuYWx5c2lzIFByb2R1Y3RzL0JQVF9BbmFseXNpc19JbnRlcm1lZGlhdGUuY3N2IikKCiNTcGxpdCAiWm9uZXMgMSBhbmQgMiIgaW50byB0d28gZW50cmllcwp0b19zcGxpdCA9IGZpbmFsXzEgJT4lIGZpbHRlcih6b25lID09ICJab25lcyAxIGFuZCAyIikgJT4lIG11dGF0ZSh6b25lID0gIlpvbmUgMSIpCmZpbmFsXzIgPSBmaW5hbF8xICU+JSBtdXRhdGUoem9uZSA9IHJlcGxhY2Uoem9uZSwgem9uZSA9PSAiWm9uZXMgMSBhbmQgMiIsICJab25lIDIiKSkKZmluYWxfMiA9IHJiaW5kKGZpbmFsXzIsIHRvX3NwbGl0KQoKI1NwbGl0ICJab25lcyAyIGFuZCAzIiBpbnRvIHR3byBlbnRyaWVzCnRvX3NwbGl0ID0gZmluYWxfMSAlPiUgZmlsdGVyKHpvbmUgPT0gIlpvbmVzIDIgYW5kIDMiKSAlPiUgbXV0YXRlKHpvbmUgPSAiWm9uZSAyIikKZmluYWxfMiA9IGZpbmFsXzIgJT4lIG11dGF0ZSh6b25lID0gcmVwbGFjZSh6b25lLCB6b25lID09ICJab25lcyAyIGFuZCAzIiwgIlpvbmUgMyIpKQpmaW5hbF8yID0gcmJpbmQoZmluYWxfMiwgdG9fc3BsaXQpCgpjb25kZW5zZSA9IGZpbmFsXzIgJT4lIHBpdm90X3dpZGVyKAogIG5hbWVzX2Zyb20gPSB6b25lLAogIHZhbHVlc19mcm9tID0gcGFnZSwKICB2YWx1ZXNfZm4gPSB1bmlxdWUobGlzdCgpKQopCmNvbmRlbnNlID0gbGVmdF9qb2luKGNvbmRlbnNlLCBmdWxsX3RheGFfbGlzdFssIGMoIlNwZWNpZXMiLCAiVW5pcXVlIiwgIkluZGljYXRvciIpXSwgYnkgPSBqb2luX2J5KG5hbWUgPT0gU3BlY2llcykpCmNvbmRlbnNlID0gY29uZGVuc2UgJT4lIG11dGF0ZShTaXRlID0gY29hbGVzY2UoVW5pcXVlLCBJbmRpY2F0b3IpKQpjb25kZW5zZSA9IGNvbmRlbnNlICU+JSByZWxvY2F0ZShTaXRlLCBVbmlxdWUsIEluZGljYXRvciwgbmFtZSwgJ1pvbmUgNCcsICdab25lIDMnLCAnWm9uZSAyJywgJ1pvbmUgMScpCmNvbmRlbnNlID0gY29uZGVuc2UgJT4lIHJlbmFtZSgKICBab25lXzEgPSAnWm9uZSAxJywKICBab25lXzIgPSAnWm9uZSAyJywKICBab25lXzMgPSAnWm9uZSAzJywKICBab25lXzQgPSAnWm9uZSA0JwopCgpjb25kZW5zZV9ub19wYWdlcyA9IGNvbmRlbnNlCmNvbmRlbnNlX25vX3BhZ2VzJFpvbmVfMSA9ICFzYXBwbHkoY29uZGVuc2Vfbm9fcGFnZXMkWm9uZV8xLCBpcy5udWxsKQpjb25kZW5zZV9ub19wYWdlcyRab25lXzIgPSAhc2FwcGx5KGNvbmRlbnNlX25vX3BhZ2VzJFpvbmVfMiwgaXMubnVsbCkKY29uZGVuc2Vfbm9fcGFnZXMkWm9uZV8zID0gIXNhcHBseShjb25kZW5zZV9ub19wYWdlcyRab25lXzMsIGlzLm51bGwpCmNvbmRlbnNlX25vX3BhZ2VzJFpvbmVfNCA9ICFzYXBwbHkoY29uZGVuc2Vfbm9fcGFnZXMkWm9uZV80LCBpcy5udWxsKQoKI0FkanVzdCBCYXNlZCBvbiBNYW51YWwgQ2hlY2tpbmcgaW4gQlBUCgojUmVtb3ZlICJQcm9ib3NjaWRhY3R5bGEgZmxhdmljaXJyYXRhIiBiZWNhdXNlIHNlYXJjaCBpZGVudGlmaWVkIHRoZSB3cm9uZyBhYmJyZXZpYXRlZCBzeW5vbnltCmNvbmRlbnNlX25vX3BhZ2VzID0gY29uZGVuc2Vfbm9fcGFnZXMgJT4lIGZpbHRlcihuYW1lICE9ICJQcm9ib3NjaWRhY3R5bGEgZmxhdmljaXJyYXRhIikKCiNBZGQgIkxhbWluYXJpYSBzZXRjaGVsbGlpIiBiZWNhdXNlIGl0IHdhcyBmb3VuZCBtYW51YWxseSBhbmQgb25seSBhcHBlYXJzIGluIGEgZGlhZ3JhbSAoc28gbm90IGluIHRleHQgc2VhcmNoKQpjb25kZW5zZV9ub19wYWdlcyA9IGNvbmRlbnNlX25vX3BhZ2VzICU+JSBhZGRfcm93KAogIFNpdGUgPSAiTiIsCiAgVW5pcXVlID0gIk4iLAogIEluZGljYXRvciA9IE5BLAogIG5hbWUgPSAiTGFtaW5hcmlhIHNldGNoZWxsaWkiLAogIFpvbmVfNCA9IFRSVUUsCiAgWm9uZV8zID0gRkFMU0UsCiAgWm9uZV8yID0gRkFMU0UsCiAgWm9uZV8xID0gRkFMU0UKKQoKI0FkZCAiRWdyZWdpYSBtZW56aWVzaWkiIGJlY2F1c2UgaXQgd2FzIGZvdW5kIG1hbnVhbGx5IHRocm91Z2ggdGhlIGluZGV4LCBidXQgb25seSBhcHBlYXJzIGJ5IGdlbnVzIGluIHRoZSB0ZXh0CmNvbmRlbnNlX25vX3BhZ2VzID0gY29uZGVuc2Vfbm9fcGFnZXMgJT4lIGFkZF9yb3coCiAgU2l0ZSA9ICJTMiIsCiAgVW5pcXVlID0gIlMyIiwKICBJbmRpY2F0b3IgPSBOQSwKICBuYW1lID0gIkVncmVnaWEgbWVuemllc2lpIiwKICBab25lXzQgPSBUUlVFLAogIFpvbmVfMyA9IFRSVUUsCiAgWm9uZV8yID0gVFJVRSwKICBab25lXzEgPSBGQUxTRQopCgojQWRkICJQYW5kYWx1cyBkYW5hZSIgYmVjYXVzZSBpdCB3YXMgZm91bmQgbWFudWFsbHkgdGhyb3VnaCB0aGUgaW5kZXgsIGJ1dCBvbmx5IGFwcGVhcnMgYnkgZ2VudXMgaW4gdGhlIHRleHQKY29uZGVuc2Vfbm9fcGFnZXMgPSBjb25kZW5zZV9ub19wYWdlcyAlPiUgYWRkX3JvdygKICBTaXRlID0gIlMyIiwKICBVbmlxdWUgPSAiUzIiLAogIEluZGljYXRvciA9IE5BLAogIG5hbWUgPSAiUGFuZGFsdXMgZGFuYWUiLAogIFpvbmVfNCA9IFRSVUUsCiAgWm9uZV8zID0gRkFMU0UsCiAgWm9uZV8yID0gRkFMU0UsCiAgWm9uZV8xID0gRkFMU0UKKQoKI0FkanVzdCAiRWN0b3BsZXVyYSBtYXJpbmEiIHRvIGluY2x1ZGUgWm9uZV8zIChmb3VuZCBtYW51YWxseSBiZWNhdXNlIG1lbnRpb25lZCBvbiB0aGF0IHBhZ2Ugd2l0aCBnZW51cyBvbmx5LCBidXQgbGlua2VkIGluIHRoZSBpbmRleCkKY29uZGVuc2Vfbm9fcGFnZXMgPSBjb25kZW5zZV9ub19wYWdlcyAlPiUgCiAgbXV0YXRlKFpvbmVfMyA9IHJlcGxhY2UoWm9uZV8zLCBuYW1lID09ICJFY3RvcGxldXJhIG1hcmluYSIsIFRSVUUpKQoKI0FkanVzdCAiSGFsb3N5ZG5hIGJyZXZpc2V0b3NhIiB0byBpbmNsdWRlIFpvbmVfNCAoZm91bmQgbWFudWFsbHkgYmVjYXVzZSBtZW50aW9uZWQgb24gdGhhdCBwYWdlIHdpdGggZ2VudXMgb25seSwgYnV0IGxpbmtlZCBpbiB0aGUgaW5kZXgpCmNvbmRlbnNlX25vX3BhZ2VzID0gY29uZGVuc2Vfbm9fcGFnZXMgJT4lIAogIG11dGF0ZShab25lXzQgPSByZXBsYWNlKFpvbmVfNCwgbmFtZSA9PSAiSGFsb3N5ZG5hIGJyZXZpc2V0b3NhIiwgVFJVRSkpCgojU29ydCB0aGUgc3BlY2llcyBsaXN0CmNvbmRlbnNlX25vX3BhZ2VzID0gY29uZGVuc2Vfbm9fcGFnZXMgJT4lIAogIGFycmFuZ2UobmFtZSkgJT4lCiAgYXJyYW5nZShkZXNjKFpvbmVfMSksIGRlc2MoWm9uZV8yKSwgZGVzYyhab25lXzMpLCBkZXNjKFpvbmVfNCkpICU+JQogIGFycmFuZ2UoZmFjdG9yKFNpdGUsIGxldmVscyA9IGMoIlMxIiwgIlMyIiwgIk4iKSkpCgojT3JnYW5pemUgc3BlY2llcyBsaXN0IGZvciBjaGkgc3F1YXJlIHRlc3QKY29udGluZ2VuY3lfdGFibGUgPSBjb25kZW5zZV9ub19wYWdlcyAlPiUgZ3JvdXBfYnkoU2l0ZSkgJT4lIHN1bW1hcmlzZSgKICBIaWdoID0gc3VtKFpvbmVfMSA9PSBUUlVFIHwKICAgICAgICAgICAgICAgWm9uZV8yID09IFRSVUUgfAogICAgICAgICAgICAgICBab25lXzMgPT0gVFJVRSksCiAgTG93ID0gc3VtKFpvbmVfMSA9PSBGQUxTRSAmIFpvbmVfMiA9PSBGQUxTRSAmIFpvbmVfMyA9PSBGQUxTRSkKKQpjb250aW5nZW5jeV90YWJsZSA9IGNvbnRpbmdlbmN5X3RhYmxlICU+JSBkcGx5cjo6c2VsZWN0KC1TaXRlKSAlPiUgYXMubWF0cml4KCkKcm93bmFtZXMoY29udGluZ2VuY3lfdGFibGUpID0gYygiTiIsICJTMSIsICJTMiIpCgpzZXQuc2VlZCgxKQp0ZXN0ID0gY2hpc3EudGVzdChjb250aW5nZW5jeV90YWJsZSwKICAgICAgICAgICAgICAgICAgY29ycmVjdCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICBzaW11bGF0ZS5wLnZhbHVlID0gVFJVRSkKdGVzdF9wb3N0X2hvYyA9IGNoaXNxLnBvc3Rob2MudGVzdChjb250aW5nZW5jeV90YWJsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAiYm9uZmVycm9uaSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2ltdWxhdGUucC52YWx1ZSA9IFRSVUUpCmBgYAoKYGBge3IgRmlndXJlIDksIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCByZXN1bHRzID0gRkFMU0V9CiMjI0ZpZ3VyZSA5IyMjCgojQ3JlYXRlIHRhYmxlIHRvIGRpc3BsYXkgcmVzdWx0cwpmb3JfcGxvdHRpbmcgPSBjb25kZW5zZV9ub19wYWdlcwpmb3JfcGxvdHRpbmcgPSBmb3JfcGxvdHRpbmcgJT4lIG11dGF0ZSgKICBVbmlxdWUgPSByZXBsYWNlKFVuaXF1ZSwhaXMubmEoVW5pcXVlKSwgIlgiKSwKICBVbmlxdWUgPSByZXBsYWNlKFVuaXF1ZSwgaXMubmEoVW5pcXVlKSwgIiIpLAogIEluZGljYXRvciA9IHJlcGxhY2UoSW5kaWNhdG9yLCFpcy5uYShJbmRpY2F0b3IpLCAiWCIpLAogIEluZGljYXRvciA9IHJlcGxhY2UoSW5kaWNhdG9yLCBpcy5uYShJbmRpY2F0b3IpLCAiIikKKQoKZm9yX3Bsb3R0aW5nID0gZm9yX3Bsb3R0aW5nICU+JQogIGd0KGdyb3VwbmFtZV9jb2wgPSAiU2l0ZSIsIGlkID0gIm15Z3QiKSAlPiUKICB0YWJfc3Bhbm5lcihsYWJlbCA9ICJJbnRlcnRpZGFsIFpvbmVzIiwKICAgICAgICAgICAgICBjb2x1bW5zID0gYyhab25lXzQsIFpvbmVfMywgWm9uZV8yLCBab25lXzEpKSAgJT4lCiAgdGFiX29wdGlvbnMocm93X2dyb3VwLmFzX2NvbHVtbiA9IFRSVUUpICAlPiUKICBndF9jb2xvcl9yb3dzKCJab25lXzQiLCBwYWxldHRlID0gYygid2hpdGUiLCAiI0QxRTdDNyIpKSAlPiUKICBndF9jb2xvcl9yb3dzKCJab25lXzMiLCBwYWxldHRlID0gYygid2hpdGUiLCAiI0JCQkVEMSIpKSAlPiUKICBndF9jb2xvcl9yb3dzKCJab25lXzIiLCBwYWxldHRlID0gYygid2hpdGUiLCAiI0JCQkVEMSIpKSAlPiUKICBndF9jb2xvcl9yb3dzKCJab25lXzEiLCBwYWxldHRlID0gYygid2hpdGUiLCAiI0JCQkVEMSIpKSAlPiUKICB0YWJfc3R5bGUoc3R5bGUgPSBjZWxsX3RleHQoc3R5bGUgPSAiaXRhbGljIiksCiAgICAgICAgICAgIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IG5hbWUpKSAlPiUKICB0YWJfc3R5bGUoCiAgICBzdHlsZSA9IGNlbGxfdGV4dChjb2xvciA9ICIjRkZGRkZGMDAiLCBzaXplID0gIngtc21hbGwiKSwKICAgIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IGMoIlpvbmVfNCIsICJab25lXzMiLCAiWm9uZV8yIiwgIlpvbmVfMSIpKQogICkgJT4lIHRhYl9zdHlsZShzdHlsZSA9IGNlbGxfdGV4dChzaXplID0gcHgoMTIpKSwKICAgICAgICAgICAgICAgICAgbG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gYygiVW5pcXVlIiwgIkluZGljYXRvciIsICJuYW1lIikpKSAlPiUKICBjb2xzX2FsaWduKGFsaWduID0gImNlbnRlciIsCiAgICAgICAgICAgICBjb2x1bW5zID0gYygiVW5pcXVlIiwgIkluZGljYXRvciIpKSAlPiUKICBjb2xzX2xhYmVsKAogICAgWm9uZV8xID0gIjEiLAogICAgWm9uZV8yID0gIjIiLAogICAgWm9uZV8zID0gIjMiLAogICAgWm9uZV80ID0gIjQiLAogICAgbmFtZSA9ICJTcGVjaWVzIiwKICAgIFVuaXF1ZSA9ICJVbmlxLlxuVG8iLAogICAgSW5kaWNhdG9yID0gIkluZGljLlxuT2YiCiAgKSAlPiUKICB0YWJfc3R5bGUoc3R5bGUgPSAgY2VsbF90ZXh0KHZfYWxpZ24gPSAibWlkZGxlIiksCiAgICAgICAgICAgIGxvY2F0aW9ucyA9IGNlbGxzX3Jvd19ncm91cHMoKSkgJT4lIHRhYl9zdHlsZSgKICAgICAgICAgICAgICBzdHlsZSA9IGNlbGxfYm9yZGVycygKICAgICAgICAgICAgICAgIHNpZGVzID0gYygiYm90dG9tIiksCiAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgICB3ZWlnaHQgPSBweCgzKQogICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgbG9jYXRpb25zID0gbGlzdChjZWxsc19jb2x1bW5fc3Bhbm5lcnMoKSwgY2VsbHNfY29sdW1uX2xhYmVscygpKQogICAgICAgICAgICApICU+JSB0YWJfc3R5bGUoCiAgICAgICAgICAgICAgc3R5bGUgPSBjZWxsX2JvcmRlcnMoCiAgICAgICAgICAgICAgICBzaWRlcyA9ICJhbGwiLAogICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgd2VpZ2h0ID0gcHgoMykKICAgICAgICAgICAgICApLAogICAgICAgICAgICAgIGxvY2F0aW9ucyA9IGxpc3QoY2VsbHNfcm93X2dyb3VwcygpKQogICAgICAgICAgICApICU+JQogIHRhYl9zdHlsZShzdHlsZSA9IGNlbGxfYm9yZGVycyhzaWRlcyA9ICJhbGwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpLAogICAgICAgICAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KCkpICU+JSB0YWJfc3R5bGUoCiAgICAgICAgICAgICAgc3R5bGUgPSBjZWxsX2JvcmRlcnMoCiAgICAgICAgICAgICAgICBzaWRlcyA9ICJib3R0b20iLAogICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgd2VpZ2h0ID0gcHgoMykKICAgICAgICAgICAgICApLAogICAgICAgICAgICAgIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkocm93cyA9IGMoMTgsIDMxLCA0MSkpCiAgICAgICAgICAgICkgJT4lIHRhYl9zdHlsZSgKICAgICAgICAgICAgICBzdHlsZSA9IGNlbGxfYm9yZGVycygKICAgICAgICAgICAgICAgIHNpZGVzID0gInJpZ2h0IiwKICAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICAgIHdlaWdodCA9IHB4KDMpCiAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSA4KQogICAgICAgICAgICApICU+JQogIAogIHRhYl9vcHRpb25zKGRhdGFfcm93LnBhZGRpbmcgPSBweCgxKSkgJT4lCiAgZGF0YV9jb2xvcigKICAgIGNvbHVtbnMgPSBVbmlxdWUsCiAgICByb3dzID0gVW5pcXVlID09ICJYIiwKICAgIHBhbGV0dGUgPSAibGlnaHRncmF5IiwKICApICU+JQogIGRhdGFfY29sb3IoCiAgICBjb2x1bW5zID0gSW5kaWNhdG9yLAogICAgcm93cyA9IEluZGljYXRvciA9PSAiWCIsCiAgICBwYWxldHRlID0gImxpZ2h0Z3JheSIsCiAgKSAlPiUKICB0YWJfb3B0aW9ucyh0YWJsZS5ib3JkZXIudG9wLnN0eWxlID0gImhpZGRlbiIpICU+JQogIHRhYl9zdHlsZShzdHlsZSA9IGNlbGxfdGV4dChhbGlnbiA9ICJjZW50ZXIiKSwKICAgICAgICAgICAgbG9jYXRpb25zID0gY2VsbHNfY29sdW1uX2xhYmVscyhjb2x1bW5zID0gbmFtZSkpCgpwYXRoID0gIkZpZ3VyZXMvRmlndXJlOS5wbmciCmd0c2F2ZShmb3JfcGxvdHRpbmcsIGZpbGVuYW1lID0gcGF0aCkKYGBgCgpJZGVudGlmaWVkIHVuaXF1ZSBhbmQgaW5kaWNhdG9yIHRheGEgcmVmbGVjdGVkIGtub3duIGVjb2xvZ2ljYWwgZGlmZmVyZW5jZXMgYmV0d2VlbiBsb2NhdGlvbnMuIE9ubHkgYSBzdWJzZXQgb2YgdW5pcXVlIGFuZCBpbmRpY2F0b3IgdGF4YSB3ZXJlIGRlc2NyaWJlZCBpbiBCZXR3ZWVuIFBhY2lmaWMgVGlkZXM6IGByIHNwcmludGYoIiUwLjFmJSUiLCBsZW5ndGgod2hpY2goY29uZGVuc2Vfbm9fcGFnZXMkU2l0ZT09Ik4iKSkvbGVuZ3RoKHdoaWNoKGZ1bGxfdGF4YV9saXN0JFVuaXF1ZT09Ik4iIHwgZnVsbF90YXhhX2xpc3QkSW5kaWNhdG9yPT0iTiIpKSAqIDEwMClgIGBzcHJpbnRmKCIlMC4xZiUlIiwgbGVuZ3RoKHdoaWNoKGNvbmRlbnNlX25vX3BhZ2VzJFNpdGU9PSJOIikpL2xlbmd0aCh3aGljaChmdWxsX3RheGFfbGlzdCRVbmlxdWU9PSJOIiB8IGZ1bGxfdGF4YV9saXN0JEluZGljYXRvcj09Ik4iKSkgKiAxMDApYCAoYHIgbGVuZ3RoKHdoaWNoKGNvbmRlbnNlX25vX3BhZ2VzJFNpdGU9PSJOIikpYCBgbGVuZ3RoKHdoaWNoKGNvbmRlbnNlX25vX3BhZ2VzJFNpdGU9PSJOIikpYC9gciBsZW5ndGgod2hpY2goZnVsbF90YXhhX2xpc3QkVW5pcXVlPT0iTiIgfCBmdWxsX3RheGFfbGlzdCRJbmRpY2F0b3I9PSJOIikpYCBgbGVuZ3RoKHdoaWNoKGZ1bGxfdGF4YV9saXN0JFVuaXF1ZT09Ik4iIHwgZnVsbF90YXhhX2xpc3QkSW5kaWNhdG9yPT0iTiIpKWApIG9mIG5lYXJzaG9yZSB0YXhhLCBgciBzcHJpbnRmKCIlMC4xZiUlIiwgbGVuZ3RoKHdoaWNoKGNvbmRlbnNlX25vX3BhZ2VzJFNpdGU9PSJTMSIpKS9sZW5ndGgod2hpY2goZnVsbF90YXhhX2xpc3QkVW5pcXVlPT0iUzEiIHwgZnVsbF90YXhhX2xpc3QkSW5kaWNhdG9yPT0iUzEiKSkgKiAxMDApYCBgc3ByaW50ZigiJTAuMWYlJSIsIGxlbmd0aCh3aGljaChjb25kZW5zZV9ub19wYWdlcyRTaXRlPT0iUzEiKSkvbGVuZ3RoKHdoaWNoKGZ1bGxfdGF4YV9saXN0JFVuaXF1ZT09IlMxIiB8IGZ1bGxfdGF4YV9saXN0JEluZGljYXRvcj09IlMxIikpICogMTAwKWAgKGByIGxlbmd0aCh3aGljaChjb25kZW5zZV9ub19wYWdlcyRTaXRlPT0iUzEiKSlgIGBsZW5ndGgod2hpY2goY29uZGVuc2Vfbm9fcGFnZXMkU2l0ZT09IlMxIikpYC9gciBsZW5ndGgod2hpY2goZnVsbF90YXhhX2xpc3QkVW5pcXVlPT0iUzEiIHwgZnVsbF90YXhhX2xpc3QkSW5kaWNhdG9yPT0iUzEiKSlgIGBsZW5ndGgod2hpY2goZnVsbF90YXhhX2xpc3QkVW5pcXVlPT0iUzEiIHwgZnVsbF90YXhhX2xpc3QkSW5kaWNhdG9yPT0iUzEiKSlgKSBvZiBTMSB0YXhhLCBhbmQgYHIgc3ByaW50ZigiJTAuMWYlJSIsIGxlbmd0aCh3aGljaChjb25kZW5zZV9ub19wYWdlcyRTaXRlPT0iUzIiKSkvbGVuZ3RoKHdoaWNoKGZ1bGxfdGF4YV9saXN0JFVuaXF1ZT09IlMyIiB8IGZ1bGxfdGF4YV9saXN0JEluZGljYXRvcj09IlMyIikpICogMTAwKWAgYHNwcmludGYoIiUwLjFmJSUiLCBsZW5ndGgod2hpY2goY29uZGVuc2Vfbm9fcGFnZXMkU2l0ZT09IlMyIikpL2xlbmd0aCh3aGljaChmdWxsX3RheGFfbGlzdCRVbmlxdWU9PSJTMiIgfCBmdWxsX3RheGFfbGlzdCRJbmRpY2F0b3I9PSJTMiIpKSAqIDEwMClgIChgciBsZW5ndGgod2hpY2goY29uZGVuc2Vfbm9fcGFnZXMkU2l0ZT09IlMyIikpYCBgbGVuZ3RoKHdoaWNoKGNvbmRlbnNlX25vX3BhZ2VzJFNpdGU9PSJTMiIpKWAvYHIgbGVuZ3RoKHdoaWNoKGZ1bGxfdGF4YV9saXN0JFVuaXF1ZT09IlMyIiB8IGZ1bGxfdGF4YV9saXN0JEluZGljYXRvcj09IlMyIikpYCBgbGVuZ3RoKHdoaWNoKGZ1bGxfdGF4YV9saXN0JFVuaXF1ZT09IlMyIiB8IGZ1bGxfdGF4YV9saXN0JEluZGljYXRvcj09IlMyIikpYCkgb2YgUzIuIEhvd2V2ZXIsIGFjcm9zcyB0aGUgc3Vic2V0IHByZXNlbnQgaW4gQmV0d2VlbiBQYWNpZmljIFRpZGVzLCBtb3JlIHRheGEgZnJvbSBTMSB3ZXJlIGNhdGVnb3JpemVkIHRvIHRoZSBoaWdoZXN0IGludGVydGlkYWwgem9uZXMgKFpvbmUgMSAtIHVwcGVybW9zdCBob3Jpem9uLCBab25lIDIgLSBoaWdoLCBhbmQgWm9uZSAzIC0gbWlkZGxlKSB0aGFuIFMyIGFuZCBOIChGaWd1cmUgOSkuIFRoZSBwcm9wb3J0aW9uIG9mIHRheGEgZnJvbSBoaWdoZXN0IGludGVydGlkYWwgem9uZXMgdmFyaWVkIHNpZ25pZmljYW50bHkgYWNyb3NzIGxvY2F0aW9ucyAoz4cyID1gciB0ZXN0JHN0YXRpc3RpY2AgYHRlc3Qkc3RhdGlzdGljYCwgcCA9IGByIHRlc3QkcC52YWx1ZWAgYHRlc3QkcC52YWx1ZWApLCBtYXRjaGluZyB0aGUgZW52aXJvbm1lbnRhbCBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlIHNpdGVzLgoKPGNlbnRlcj4KCiFbKkZpZ3VyZSA5OiBDaGFydCBoYWJpdGF0IGluZm9ybWF0aW9uIGFib3V0IHVuaXF1ZSBhbmQgaW5kaWNhdG9yIHNwZWNpZXMgcHJlc2VudCBpbiBCZXR3ZWVuIFBhY2lmaWMgVGlkZXMqXShgciBwYXN0ZTAocGF0aClgKQoKPC9jZW50ZXI+CgojIyMgU3VwcG9ydGluZyBJbmZvcm1hdGlvbgoKYGBge3IgU3VwcG9ydGluZyBGaWd1cmUgMX0KIyMjU3VwcG9ydGluZyBGaWd1cmUgMSMjIwoKcGF0aCA9ICJGaWd1cmVzL0ZpZ3VyZVMxLiIKc2F2ZV9wZGZfcG5nKAogIHBsb3QgPSBoZWF0bWFwX0FTViRwbG90LAogIHBhdGggPSBwYXRoLAogIHcgPSAxNjksCiAgaCA9IDMwMCwKICB1ID0gIm1tIiwKICBiZyA9ICJ0cmFuc3BhcmVudCIsCiAgZHBpID0gNjAwCikKYGBgCgo8Y2VudGVyPgoKIVsqRmlndXJlIFMxOiBIZWF0IG1hcCBvZiBpZGVudGlmaWVkIGluZGljYXRvciBBU1ZzIGZvciBhbGwgdGhyZWUgbG9jYXRpb25zIG92ZXIgdGltZSwgc2NhbGVkIGJ5IHRoZSBudW1iZXIgb2YgcmVwbGljYXRlcyB0aGF0IGRldGVjdGVkIHRoYXQgc3BlY2llcy4qXShgciBwYXN0ZTAocGF0aCwgInBuZyIpYCkKCjwvY2VudGVyPgoKYGBge3IgU3VwcG9ydGluZyBUYWJsZSAxfQojI1N1cHBvcnRpbmcgVGFibGUgMSMjIwoKb3ZlcmxhcF90YWJsZQp3cml0ZS5jc3Yob3ZlcmxhcF90YWJsZSwgIkFuYWx5c2lzIFByb2R1Y3RzL1RhYmxlUzEuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKQnkgYW5hbHl6aW5nIG9jY3VycmVuY2UgZGF0YSBmcm9tIHRoZSBHbG9iYWwgQmlvZGl2ZXJzaXR5IEluZm9ybWF0aW9uIEZhY2lsaXR5IChvbiBgciBTeXMuRGF0ZSgpYCBgU3lzLkRhdGUoKWApLCB3ZSBjb25maXJtZWQgdGhhdCBgciBwZXJjZW50YWdlcyRjb3VudFs2XWAgYHBlcmNlbnRhZ2VzJGNvdW50WzZdYCBvZiBgYGAgciBzdW0ocGVyY2VudGFnZXMkY291bnQpYGBzdW0ocGVyY2VudGFnZXMkY291bnQpIGBgYCBpZGVudGlmaWVkIHNwZWNpZXMgKGByIHNwcmludGYoIiUwLjFmJSUiLCBwZXJjZW50YWdlcyRwZXJbNl0gKiAxMDApYCBgc3ByaW50ZigiJTAuMWYlJSIsIHBlcmNlbnRhZ2VzJHBlcls2XSAqIDEwMClgKSBoYXZlIG9jY3VycmVuY2UgcmVjb3JkcyBhdCBQaWxsYXIgUG9pbnQsIHNwZWNpZmljYWxseS4gQW4gYWRkaXRpb25hbCBgciBwZXJjZW50YWdlcyRjb3VudFs1XWAgYHBlcmNlbnRhZ2VzJGNvdW50WzVdYCBpZGVudGlmaWVkIHNwZWNpZXMgKGByIHNwcmludGYoIiUwLjFmJSUiLCBwZXJjZW50YWdlcyRwZXJbNV0gKiAxMDApYCBgc3ByaW50ZigiJTAuMWYlJSIsIHBlcmNlbnRhZ2VzJHBlcls1XSAqIDEwMClgKSBoYXZlIG9jY3VycmVuY2UgcmVjb3JkcyBpbiB0aGUgQ2FsaWZvcm5pYSBDdXJyZW50IFN5c3RlbSAoQ0NTKSBhbmQga25vd24gcmFuZ2VzIHRoYXQgZW5jb21wYXNzIFBpbGxhciBQb2ludC4gT2YgdGhlIHJlbWFpbmluZyBzcGVjaWVzLCBzb21lIG9ubHkgZnVsZmlsbGVkIG9uZSBvZiB0d28gY3JpdGVyaWE7IGByIHBlcmNlbnRhZ2VzJGNvdW50WzRdYCBgcGVyY2VudGFnZXMkY291bnRbNF1gIGlkZW50aWZpZWQgc3BlY2llcyAoYHIgc3ByaW50ZigiJTAuMWYlJSIsIHBlcmNlbnRhZ2VzJHBlcls0XSAqIDEwMClgIGBzcHJpbnRmKCIlMC4xZiUlIiwgcGVyY2VudGFnZXMkcGVyWzRdICogMTAwKWApIGhhZCBvY2N1cnJlbmNlIHJlY29yZHMgaW4gdGhlIENDUyBidXQga25vd24gcmFuZ2VzIHRoYXQgZGlkIG5vdCBlbmNvbXBhc3MgUGlsbGFyIFBvaW50IGFuZCBgciBwZXJjZW50YWdlcyRjb3VudFszXWAgYHBlcmNlbnRhZ2VzJGNvdW50WzNdYCBpZGVudGlmaWVkIHNwZWNpZXMgKGByIHNwcmludGYoIiUwLjFmJSUiLCBwZXJjZW50YWdlcyRwZXJbM10gKiAxMDApYCBgc3ByaW50ZigiJTAuMWYlJSIsIHBlcmNlbnRhZ2VzJHBlclszXSAqIDEwMClgKSBoYWQgcmFuZ2VzIHRoYXQgZW5jb21wYXNzIFBpbGxhciBQb2ludCBidXQgbm8gb2NjdXJyZW5jZSByZWNvcmRzIGluIHRoZSBDQ1MuIEFkZGl0aW9uYWxseSwgYHIgcGVyY2VudGFnZXMkY291bnRbMV1gIGBwZXJjZW50YWdlcyRjb3VudFsxXWAgaWRlbnRpZmllZCBzcGVjaWVzIChgciBzcHJpbnRmKCIlMC4xZiUlIiwgcGVyY2VudGFnZXMkcGVyWzFdICogMTAwKWAgYHNwcmludGYoIiUwLjFmJSUiLCBwZXJjZW50YWdlcyRwZXJbMV0gKiAxMDApYCkgaGFkIG5laXRoZXIgb2NjdXJyZW5jZSByZWNvcmRzIGluIHRoZSBDQ1Mgbm9yIGtub3duIHJhbmdlcyB0aGF0IGVuY29tcGFzc2VkIFBpbGxhciBQb2ludC4gRmluYWxseSwgYHIgcGVyY2VudGFnZXMkY291bnRbMl1gIGBwZXJjZW50YWdlcyRjb3VudFsyXWAgaWRlbnRpZmllZCBzcGVjaWVzIChgciBzcHJpbnRmKCIlMC4xZiUlIiwgcGVyY2VudGFnZXMkcGVyWzJdICogMTAwKWAgYHNwcmludGYoIiUwLjFmJSUiLCBwZXJjZW50YWdlcyRwZXJbMl0gKiAxMDApYCkgbGFja2VkIHN1ZmZpY2llbnQgb2NjdXJyZW5jZSByZWNvcmRzIGluIEdCSUYgdG8gbWFrZSBhbnkgZGVzaWduYXRpb24sIGFuZCBgciBwZXJjZW50YWdlcyRjb3VudFs3XWAgYHBlcmNlbnRhZ2VzJGNvdW50WzddYCBpZGVudGlmaWVkIHNwZWNpZXMgKGByIHNwcmludGYoIiUwLjFmJSUiLCBwZXJjZW50YWdlcyRwZXJbN10gKiAxMDApYCBgc3ByaW50ZigiJTAuMWYlJSIsIHBlcmNlbnRhZ2VzJHBlcls3XSAqIDEwMClgKSBkaWQgbm90IGhhdmUgc3BlY2llcy1sZXZlbCByZWNvcmRzIGluIEdCSUYuIEZ1bGwgZGV0YWlscyBieSBzcGVjaWVzIGNhbiBiZSBmb3VuZCBpbiBUYWJsZSBTMi4KCmBgYHtyIFN1cHBvcnRpbmcgVGFibGUgMn0KIyNTdXBwb3J0aW5nIFRhYmxlIDIjIyMKCkdCSUZfc3VtbWFyeQoKd3JpdGUuY3N2KEdCSUZfc3VtbWFyeSwgIkFuYWx5c2lzIFByb2R1Y3RzL1RhYmxlUzIuY3N2Iiwgcm93Lm5hbWVzID0gVFJVRSkKYGBgCgojIyMgQ29kZSBmb3IgTWFraW5nIFZlcnNpb25zIG9mIEZpZ3VyZXMgZm9yIFBvd2VyUG9pbnQKCipGaWd1cmUgMyoKCmBgYHtyLCBGaWd1cmUgMyBGb3IgUG93ZXJwb2ludCwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIHJlc3VsdHMgPSBGQUxTRSwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZSd9CiMjI1ZlcnNpb24gb2YgRmlndXJlIDMgb3B0aW1pemVkIGZvciBQb3dlclBvaW50IHNsaWRlcy9hbmltYXRpb25zIyMjCgpncmFwaCA9IHNhbXBsZV9zY2hlbWEKCmlmICghZGlyLmV4aXN0cygiRmlndXJlcy9Qb3dlclBvaW50IikpIHsKICBkaXIuY3JlYXRlKCJGaWd1cmVzL1Bvd2VyUG9pbnQiLCByZWN1cnNpdmUgPSBUUlVFKQp9CgpmaWxlbmFtZSA9IHBhc3RlMCgic2FtcGxlX3NjaGVtYV9mdWxsLnBkZiIpCnBhdGggPSBwYXN0ZTAoIkZpZ3VyZXMvUG93ZXJQb2ludC8iLCBmaWxlbmFtZSkKcGRmKHBhdGgsIHdpZHRoID0gMTMsIGhlaWdodCA9IDQuMykKcHJpbnQoZ3JhcGgpCmRldi5vZmYoKQoKZ3JhcGgkbGF5ZXJzW1sxXV0gPC0gTlVMTAoKYWxwaGEgPSBjKDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDApCgpmb3IgKGkgaW4gMToxMikgewogIGFscGhhW2ldID0gMQogIGdyYXBoIDwtIGdyYXBoICsKICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZChkaXJlY3Rpb24gPSAtMSwgYWxwaGEgPSBhbHBoYSkgKwogICAgc2NhbGVfZmlsbF92aXJpZGlzX2QoZGlyZWN0aW9uID0gLTEsIGFscGhhID0gYWxwaGEpCiAgZmlsZW5hbWUgPSBwYXN0ZTAoInNhbXBsZV9zY2hlbWEiLCBpLCAiLnBkZiIpCiAgcGF0aCA9IHBhc3RlMCgiRmlndXJlcy9Qb3dlclBvaW50LyIsIGZpbGVuYW1lKQogIHBkZihwYXRoLCB3aWR0aCA9IDEzLCBoZWlnaHQgPSA0LjMpCiAgcHJpbnQoZ3JhcGgpCiAgZGV2Lm9mZigpCn0KYGBgCgoqRmlndXJlIDQqCgpgYGB7ciwgRmlndXJlIDQgRm9yIFBvd2VycG9pbnQsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCByZXN1bHRzID0gRkFMU0UsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLWhpZGUnfQojIyNWZXJzaW9uIG9mIEZpZ3VyZSA0IG9wdGltaXplZCBmb3IgUG93ZXJQb2ludCBzbGlkZXMvYW5pbWF0aW9ucyMjIwoKcCA8LSBnZ3RyZWU6OmdndHJlZShwdF9waHlzZXEsICBsYXlvdXQgPSAicmVjdGFuZ3VsYXIiKQoKb3JkZXJlZF9uYW1lcyA9IGdndHJlZTo6Z2V0X3RheGFfbmFtZShwKQpvcmRlcmVkX25hbWVzID0gdW5pcXVlKG9yZGVyZWRfbmFtZXMpCm9yZGVyZWRfbmFtZXNbbWF0Y2gocm93bmFtZXModGF4X3RhYmxlKHB0X3BoeXNlcSkpLCBvcmRlcmVkX25hbWVzKV0gPSB0YXhfdGFibGUocHRfcGh5c2VxKVssICJQaHlsdW0iXQpvcmRlcmVkX25hbWVzID0gdW5pcXVlKG9yZGVyZWRfbmFtZXMpCgpuYW1lcyhjb2xvcnNfb3JkZXJlZCkgPSBvcmRlcmVkX25hbWVzCgpwID0gcCArIGdlb21fZnJ1aXQoCiAgZ2VvbSA9IGdlb21fdGlsZSwKICBtYXBwaW5nID0gYWVzKGZpbGwgPSBQaHlsdW0pLAogIHdpZHRoID0gMywKICBzaG93LmxlZ2VuZCA9IEZBTFNFCikgICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3JzX29yZGVyZWQpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yc19vcmRlcmVkKQoKcCA9IHAgKyBnZ3RyZWU6Omdlb21faGlsaWdodCgKICBkYXRhID0gcGh5bGFfbm9kZXMsCiAgbWFwcGluZyA9IGFlcyhub2RlID0gbm9kZSwgZmlsbCA9IG5vZGVfcGh5bHVtKSwKICBzaG93LmxlZ2VuZCA9IEZBTFNFCikKCnAgPSBwICsKICB0aGVtZSgKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICd0cmFuc3BhcmVudCcpLAogICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAndHJhbnNwYXJlbnQnLCBjb2xvciA9IE5BKSwKICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICd0cmFuc3BhcmVudCcpLAogICAgbGVnZW5kLmJveC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAndHJhbnNwYXJlbnQnKQogICkKCmdnc2F2ZSgKICAiRmlndXJlcy9Qb3dlclBvaW50L3BoeWxvLnBkZiIsCiAgcGxvdCA9IHAsCiAgd2lkdGggPSA0LjQ5LAogIGhlaWdodCA9IDcuMDYsCiAgZHBpID0gMzAwLAogIGJnID0gJ3RyYW5zcGFyZW50JwopCmBgYAoKKkZpZ3VyZSA2KgoKYGBge3IsIEZpZ3VyZSA2IEZvciBQb3dlcnBvaW50LCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgcmVzdWx0cyA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJ30KIyMjVmVyc2lvbiBvZiBGaWd1cmUgNiBvcHRpbWl6ZWQgZm9yIFBvd2VyUG9pbnQgc2xpZGVzL2FuaW1hdGlvbnMjIyMKCmdyYXBoID0gaGVhdG1hcF90YXhhJHBsb3QKCnBhdGggPSAiRmlndXJlcy9Qb3dlclBvaW50L2luZGljYXRvcl9maWd1cmUucG5nIgpnZ3NhdmUoCiAgZmlsZW5hbWUgPSBwYXRoLAogIHBsb3QgPSBncmFwaCwKICB3aWR0aCA9IDEzLAogIGhlaWdodCA9IDYuNjkKKQpgYGAKCipGaWd1cmUgNyoKCmBgYHtyLCBGaWd1cmUgNyBGb3IgUG93ZXJwb2ludCwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIHJlc3VsdHMgPSBGQUxTRSwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZSd9CiMjI1ZlcnNpb24gb2YgRmlndXJlIDcgb3B0aW1pemVkIGZvciBQb3dlclBvaW50IHNsaWRlcy9hbmltYXRpb25zIyMjCgphbHBoYSA9IGMoMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCkKZ3JhcGggPSBOTURTX1BBTV9mdWxsJE5NRFMgKwogIGdndGl0bGUoIk5NRFMgT3JkaW5hdGlvbiAoSmFjY2FyZCBEaXNzaW1pbGFyaXR5KSIpICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDE4KQoKZmlsZW5hbWUgPSBwYXN0ZSgiTk1EU19maWd1cmVfZnVsbC5wZGYiKQpwYXRoID0gcGFzdGUoIkZpZ3VyZXMvUG93ZXJQb2ludC8iLCBmaWxlbmFtZSkKcGRmKHBhdGgsIHdpZHRoID0gMTEuOTcsIGhlaWdodCA9IDYuMTQpCnByaW50KGdyYXBoKQpkZXYub2ZmKCkKCmdyYXBoJGxheWVyc1tbMl1dIDwtIE5VTEwKCmdyYXBoID0gZ3JhcGggKwogIHN0YXRfZWxsaXBzZSgKICAgIGFlcyhncm91cCA9IExvY2F0aW9uKSwKICAgIHR5cGUgPSAidCIsCiAgICBsaW5ldHlwZSA9IDIsCiAgICBhbHBoYSA9IDAKICApCgpmb3IgKGkgaW4gMToxMikgewogIGFscGhhW2ldID0gMQogIGdyYXBoIDwtIGdyYXBoICsKICAgIHZpcmlkaXM6OnNjYWxlX2NvbG9yX3ZpcmlkaXMoCiAgICAgIGRpc2NyZXRlID0gVFJVRSwKICAgICAgYmVnaW4gPSAwLAogICAgICBlbmQgPSAuOTcsCiAgICAgIGRpcmVjdGlvbiA9IC0xLAogICAgICBhbHBoYSA9IGFscGhhCiAgICApCiAgZmlsZW5hbWUgPSBwYXN0ZSgiTk1EU19maWd1cmUiLCBpLCAiLnBkZiIpCiAgcGF0aCA9IHBhc3RlKCJGaWd1cmVzL1Bvd2VyUG9pbnQvIiwgZmlsZW5hbWUpCiAgcGRmKHBhdGgsIHdpZHRoID0gMTEuOTcsIGhlaWdodCA9IDYuMTQpCiAgcHJpbnQoZ3JhcGgpCiAgZGV2Lm9mZigpCiAgYWxwaGFbaV0gPSAuMgp9CmBgYAoKIyMjIFNlc3Npb24gSW5mbwoKYGBge3J9CiNJZiByZW52OjpyZXN0b3JlKCkgaXNuJ3Qgd29ya2luZyBmb3IgeW91LCB0aGlzIGlzIHdoZXJlIHlvdSBjYW4gZmluYWwgdGhlIHZlcnNpb24gbnVtYmVycyBvZiB0aGUgcGFja2FnZXMgd2UgdXNlZCwgc28geW91IGNhbiB0cnkgdG8gY3JlYXRlIGEgc2ltaWxhciB3b3JraW5nIGVudmlyb25tZW50LgoKc2Vzc2lvbkluZm8oKQpgYGAK